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 "grit/theme_resources.h"
43 #include "third_party/skia/include/core/SkColor.h"
44 #include "ui/base/l10n/l10n_util.h"
45 #include "ui/base/resource/resource_bundle.h"
46 #include "ui/gfx/canvas.h"
47 #include "ui/gfx/image/image.h"
48 #include "ui/gfx/image/image_skia.h"
49 #include "ui/gfx/path.h"
50 #include "ui/gfx/skia_util.h"
51 #include "ui/gfx/text_elider.h"
52 #include "ui/native_theme/native_theme.h"
53 #include "ui/views/controls/button/blue_button.h"
54 #include "ui/views/controls/button/image_button.h"
55 #include "ui/views/controls/button/label_button.h"
56 #include "ui/views/controls/button/menu_button.h"
57 #include "ui/views/controls/label.h"
58 #include "ui/views/controls/link.h"
59 #include "ui/views/controls/separator.h"
60 #include "ui/views/controls/styled_label.h"
61 #include "ui/views/controls/textfield/textfield.h"
62 #include "ui/views/controls/webview/webview.h"
63 #include "ui/views/layout/grid_layout.h"
64 #include "ui/views/layout/layout_constants.h"
65 #include "ui/views/widget/widget.h"
69 // Helpers --------------------------------------------------------------------
71 const int kFixedMenuWidth
= 250;
72 const int kButtonHeight
= 32;
73 const int kFixedGaiaViewHeight
= 440;
74 const int kFixedGaiaViewWidth
= 360;
75 const int kFixedAccountRemovalViewWidth
= 280;
76 const int kFixedSwitchUserViewWidth
= 320;
77 const int kLargeImageSide
= 88;
79 const int kVerticalSpacing
= 16;
81 // Creates a GridLayout with a single column. This ensures that all the child
82 // views added get auto-expanded to fill the full width of the bubble.
83 views::GridLayout
* CreateSingleColumnLayout(views::View
* view
, int width
) {
84 views::GridLayout
* layout
= new views::GridLayout(view
);
85 view
->SetLayoutManager(layout
);
87 views::ColumnSet
* columns
= layout
->AddColumnSet(0);
88 columns
->AddColumn(views::GridLayout::FILL
, views::GridLayout::FILL
, 0,
89 views::GridLayout::FIXED
, width
, width
);
93 views::Link
* CreateLink(const base::string16
& link_text
,
94 views::LinkListener
* listener
) {
95 views::Link
* link_button
= new views::Link(link_text
);
96 link_button
->SetHorizontalAlignment(gfx::ALIGN_LEFT
);
97 link_button
->SetUnderline(false);
98 link_button
->set_listener(listener
);
102 gfx::ImageSkia
CreateSquarePlaceholderImage(int size
) {
104 bitmap
.allocPixels(SkImageInfo::MakeA8(size
, size
));
105 bitmap
.eraseARGB(0, 0, 0, 0);
106 return gfx::ImageSkia::CreateFrom1xBitmap(bitmap
);
109 bool HasAuthError(Profile
* profile
) {
110 const SigninErrorController
* error
=
111 profiles::GetSigninErrorController(profile
);
112 return error
&& error
->HasError();
115 std::string
GetAuthErrorAccountId(Profile
* profile
) {
116 const SigninErrorController
* error
=
117 profiles::GetSigninErrorController(profile
);
119 return std::string();
121 return error
->error_account_id();
124 std::string
GetAuthErrorUsername(Profile
* profile
) {
125 const SigninErrorController
* error
=
126 profiles::GetSigninErrorController(profile
);
128 return std::string();
130 return error
->error_username();
133 // BackgroundColorHoverButton -------------------------------------------------
135 // A custom button that allows for setting a background color when hovered over.
136 class BackgroundColorHoverButton
: public views::LabelButton
{
138 BackgroundColorHoverButton(views::ButtonListener
* listener
,
139 const base::string16
& text
,
140 const gfx::ImageSkia
& icon
)
141 : views::LabelButton(listener
, text
) {
142 SetImageLabelSpacing(views::kItemLabelSpacing
);
143 SetBorder(views::Border::CreateEmptyBorder(
144 0, views::kButtonHEdgeMarginNew
, 0, views::kButtonHEdgeMarginNew
));
145 SetMinSize(gfx::Size(0,
146 kButtonHeight
+ views::kRelatedControlVerticalSpacing
));
147 SetImage(STATE_NORMAL
, icon
);
151 virtual ~BackgroundColorHoverButton() {}
154 // views::LabelButton:
155 virtual void OnPaint(gfx::Canvas
* canvas
) override
{
156 if ((state() == STATE_PRESSED
) ||
157 (state() == STATE_HOVERED
)) {
158 canvas
->DrawColor(GetNativeTheme()->GetSystemColor(
159 ui::NativeTheme::kColorId_ButtonHoverBackgroundColor
));
161 LabelButton::OnPaint(canvas
);
164 DISALLOW_COPY_AND_ASSIGN(BackgroundColorHoverButton
);
167 // SizedContainer -------------------------------------------------
169 // A simple container view that takes an explicit preferred size.
170 class SizedContainer
: public views::View
{
172 explicit SizedContainer(const gfx::Size
& preferred_size
)
173 : preferred_size_(preferred_size
) {}
175 virtual gfx::Size
GetPreferredSize() const override
{
176 return preferred_size_
;
180 gfx::Size preferred_size_
;
185 // RightAlignedIconLabelButton -------------------------------------------------
187 // A custom LabelButton that has a centered text and right aligned icon.
188 class RightAlignedIconLabelButton
: public views::LabelButton
{
190 RightAlignedIconLabelButton(views::ButtonListener
* listener
,
191 const base::string16
& text
)
192 : views::LabelButton(listener
, text
) {
196 virtual void Layout() override
{
197 // This layout trick keeps the text left-aligned and the icon right-aligned.
198 SetHorizontalAlignment(gfx::ALIGN_RIGHT
);
199 views::LabelButton::Layout();
200 label()->SetHorizontalAlignment(gfx::ALIGN_CENTER
);
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
{
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
) {
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 virtual void OnPaint(gfx::Canvas
* canvas
) override
{
251 // Display the profile picture as a circle.
252 canvas
->ClipPath(circular_mask_
, true);
253 views::LabelButton::OnPaint(canvas
);
256 virtual void PaintChildren(gfx::Canvas
* canvas
,
257 const views::CullSet
& cull_set
) override
{
258 // Display any children (the "change photo" overlay) as a circle.
259 canvas
->ClipPath(circular_mask_
, true);
260 View::PaintChildren(canvas
, cull_set
);
264 // views::CustomButton:
265 virtual void StateChanged() override
{
267 (state() == STATE_PRESSED
|| state() == STATE_HOVERED
|| HasFocus());
269 photo_overlay_
->SetVisible(show_overlay
);
272 virtual void OnFocus() override
{
273 views::LabelButton::OnFocus();
275 photo_overlay_
->SetVisible(true);
278 virtual void OnBlur() override
{
279 views::LabelButton::OnBlur();
280 // Don't hide the overlay if it's being shown as a result of a mouseover.
281 if (photo_overlay_
&& state() != STATE_HOVERED
)
282 photo_overlay_
->SetVisible(false);
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
{
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));
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);
353 // views::ButtonListener:
354 virtual void ButtonPressed(views::Button
* sender
,
355 const ui::Event
& event
) override
{
356 if (profile_name_textfield_
) {
357 profile_name_textfield_
->SetVisible(true);
358 profile_name_textfield_
->SetText(GetText());
359 profile_name_textfield_
->SelectAll(false);
360 profile_name_textfield_
->RequestFocus();
364 // views::LabelButton:
365 virtual bool OnKeyReleased(const ui::KeyEvent
& event
) override
{
366 // Override CustomButton's implementation, which presses the button when
367 // you press space and clicks it when you release space, as the space can be
368 // part of the new profile name typed in the textfield.
372 virtual void Layout() override
{
373 if (profile_name_textfield_
)
374 profile_name_textfield_
->SetBounds(0, 0, width(), height());
375 RightAlignedIconLabelButton::Layout();
378 virtual void OnFocus() override
{
379 RightAlignedIconLabelButton::OnFocus();
380 SetState(STATE_HOVERED
);
383 virtual void OnBlur() override
{
384 RightAlignedIconLabelButton::OnBlur();
385 SetState(STATE_NORMAL
);
388 // Textfield that is shown when editing the profile name. Can be NULL if
389 // the profile name isn't allowed to be edited (e.g. for guest profiles).
390 views::Textfield
* profile_name_textfield_
;
392 DISALLOW_COPY_AND_ASSIGN(EditableProfileName
);
395 // A title card with one back button right aligned and one label center aligned.
396 class TitleCard
: public views::View
{
398 TitleCard(const base::string16
& message
, views::ButtonListener
* listener
,
399 views::ImageButton
** back_button
) {
400 back_button_
= new views::ImageButton(listener
);
401 back_button_
->SetImageAlignment(views::ImageButton::ALIGN_LEFT
,
402 views::ImageButton::ALIGN_MIDDLE
);
403 ui::ResourceBundle
* rb
= &ui::ResourceBundle::GetSharedInstance();
404 back_button_
->SetImage(views::ImageButton::STATE_NORMAL
,
405 rb
->GetImageSkiaNamed(IDR_BACK
));
406 back_button_
->SetImage(views::ImageButton::STATE_HOVERED
,
407 rb
->GetImageSkiaNamed(IDR_BACK_H
));
408 back_button_
->SetImage(views::ImageButton::STATE_PRESSED
,
409 rb
->GetImageSkiaNamed(IDR_BACK_P
));
410 back_button_
->SetImage(views::ImageButton::STATE_DISABLED
,
411 rb
->GetImageSkiaNamed(IDR_BACK_D
));
412 back_button_
->SetFocusable(true);
413 *back_button
= back_button_
;
415 title_label_
= new views::Label(message
);
416 title_label_
->SetHorizontalAlignment(gfx::ALIGN_CENTER
);
417 const gfx::FontList
& medium_font_list
=
418 rb
->GetFontList(ui::ResourceBundle::MediumFont
);
419 title_label_
->SetFontList(medium_font_list
);
421 AddChildView(back_button_
);
422 AddChildView(title_label_
);
425 // Creates a new view that has the |title_card| with horizontal padding at the
426 // top, an edge-to-edge separator below, and the specified |view| at the
428 static views::View
* AddPaddedTitleCard(views::View
* view
,
429 TitleCard
* title_card
,
431 views::View
* titled_view
= new views::View();
432 views::GridLayout
* layout
= new views::GridLayout(titled_view
);
433 titled_view
->SetLayoutManager(layout
);
435 // Column set 0 is a single column layout with horizontal padding at left
436 // and right, and column set 1 is a single column layout with no padding.
437 views::ColumnSet
* columns
= layout
->AddColumnSet(0);
438 columns
->AddPaddingColumn(1, views::kButtonHEdgeMarginNew
);
439 int available_width
= width
- 2 * views::kButtonHEdgeMarginNew
;
440 columns
->AddColumn(views::GridLayout::FILL
, views::GridLayout::FILL
, 0,
441 views::GridLayout::FIXED
, available_width
, available_width
);
442 columns
->AddPaddingColumn(1, views::kButtonHEdgeMarginNew
);
443 layout
->AddColumnSet(1)->AddColumn(views::GridLayout::FILL
,
444 views::GridLayout::FILL
, 0,views::GridLayout::FIXED
, width
, width
);
446 layout
->StartRowWithPadding(1, 0, 0, kVerticalSpacing
);
447 layout
->AddView(title_card
);
448 layout
->StartRowWithPadding(1, 1, 0, kVerticalSpacing
);
449 layout
->AddView(new views::Separator(views::Separator::HORIZONTAL
));
451 layout
->StartRow(1, 1);
452 layout
->AddView(view
);
458 virtual void Layout() override
{
459 int back_button_width
= back_button_
->GetPreferredSize().width();
460 back_button_
->SetBounds(0, 0, back_button_width
, height());
461 int label_padding
= back_button_width
+ views::kButtonHEdgeMarginNew
;
462 int label_width
= width() - 2 * label_padding
;
463 DCHECK_GT(label_width
, 0);
464 title_label_
->SetBounds(label_padding
, 0, label_width
, height());
467 virtual gfx::Size
GetPreferredSize() const override
{
468 int height
= std::max(title_label_
->GetPreferredSize().height(),
469 back_button_
->GetPreferredSize().height());
470 return gfx::Size(width(), height
);
473 views::ImageButton
* back_button_
;
474 views::Label
* title_label_
;
476 DISALLOW_COPY_AND_ASSIGN(TitleCard
);
479 // ProfileChooserView ---------------------------------------------------------
482 ProfileChooserView
* ProfileChooserView::profile_bubble_
= NULL
;
483 bool ProfileChooserView::close_on_deactivate_for_testing_
= true;
486 void ProfileChooserView::ShowBubble(
487 profiles::BubbleViewMode view_mode
,
488 profiles::TutorialMode tutorial_mode
,
489 const signin::ManageAccountsParams
& manage_accounts_params
,
490 views::View
* anchor_view
,
491 views::BubbleBorder::Arrow arrow
,
492 views::BubbleBorder::BubbleAlignment border_alignment
,
495 if (tutorial_mode
!= profiles::TUTORIAL_MODE_NONE
) {
496 profile_bubble_
->tutorial_mode_
= tutorial_mode
;
497 profile_bubble_
->ShowView(view_mode
, profile_bubble_
->avatar_menu_
.get());
502 profile_bubble_
= new ProfileChooserView(anchor_view
, arrow
, browser
,
503 view_mode
, tutorial_mode
, manage_accounts_params
.service_type
);
504 views::BubbleDelegateView::CreateBubble(profile_bubble_
);
505 profile_bubble_
->set_close_on_deactivate(close_on_deactivate_for_testing_
);
506 profile_bubble_
->SetAlignment(border_alignment
);
507 profile_bubble_
->GetWidget()->Show();
508 profile_bubble_
->SetArrowPaintType(views::BubbleBorder::PAINT_NONE
);
512 bool ProfileChooserView::IsShowing() {
513 return profile_bubble_
!= NULL
;
517 void ProfileChooserView::Hide() {
519 profile_bubble_
->GetWidget()->Close();
522 ProfileChooserView::ProfileChooserView(views::View
* anchor_view
,
523 views::BubbleBorder::Arrow arrow
,
525 profiles::BubbleViewMode view_mode
,
526 profiles::TutorialMode tutorial_mode
,
527 signin::GAIAServiceType service_type
)
528 : BubbleDelegateView(anchor_view
, arrow
),
530 view_mode_(view_mode
),
531 tutorial_mode_(tutorial_mode
),
532 gaia_service_type_(service_type
) {
533 // Reset the default margins inherited from the BubbleDelegateView.
534 // Add a small bottom inset so that the bubble's rounded corners show up.
535 set_margins(gfx::Insets(0, 0, 1, 0));
536 set_background(views::Background::CreateSolidBackground(
537 GetNativeTheme()->GetSystemColor(
538 ui::NativeTheme::kColorId_DialogBackground
)));
541 avatar_menu_
.reset(new AvatarMenu(
542 &g_browser_process
->profile_manager()->GetProfileInfoCache(),
545 avatar_menu_
->RebuildMenu();
547 ProfileOAuth2TokenService
* oauth2_token_service
=
548 ProfileOAuth2TokenServiceFactory::GetForProfile(browser_
->profile());
549 if (oauth2_token_service
)
550 oauth2_token_service
->AddObserver(this);
553 ProfileChooserView::~ProfileChooserView() {
554 ProfileOAuth2TokenService
* oauth2_token_service
=
555 ProfileOAuth2TokenServiceFactory::GetForProfile(browser_
->profile());
556 if (oauth2_token_service
)
557 oauth2_token_service
->RemoveObserver(this);
560 void ProfileChooserView::ResetView() {
561 open_other_profile_indexes_map_
.clear();
562 delete_account_button_map_
.clear();
563 reauth_account_button_map_
.clear();
564 manage_accounts_link_
= NULL
;
565 signin_current_profile_link_
= NULL
;
566 auth_error_email_button_
= NULL
;
567 current_profile_photo_
= NULL
;
568 current_profile_name_
= NULL
;
569 users_button_
= NULL
;
570 go_incognito_button_
= NULL
;
572 add_account_link_
= NULL
;
573 gaia_signin_cancel_button_
= NULL
;
574 remove_account_button_
= NULL
;
575 account_removal_cancel_button_
= NULL
;
576 add_person_button_
= NULL
;
577 disconnect_button_
= NULL
;
578 switch_user_cancel_button_
= NULL
;
579 tutorial_sync_settings_ok_button_
= NULL
;
580 tutorial_close_button_
= NULL
;
581 tutorial_sync_settings_link_
= NULL
;
582 tutorial_see_whats_new_button_
= NULL
;
583 tutorial_not_you_link_
= NULL
;
584 tutorial_learn_more_link_
= NULL
;
587 void ProfileChooserView::Init() {
588 // If view mode is PROFILE_CHOOSER but there is an auth error, force
589 // ACCOUNT_MANAGEMENT mode.
590 if (view_mode_
== profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER
&&
591 HasAuthError(browser_
->profile()) &&
592 switches::IsEnableAccountConsistency() &&
593 avatar_menu_
->GetItemAt(avatar_menu_
->GetActiveProfileIndex()).
595 view_mode_
= profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT
;
598 // The arrow keys can be used to tab between items.
599 AddAccelerator(ui::Accelerator(ui::VKEY_DOWN
, ui::EF_NONE
));
600 AddAccelerator(ui::Accelerator(ui::VKEY_UP
, ui::EF_NONE
));
602 ShowView(view_mode_
, avatar_menu_
.get());
605 void ProfileChooserView::OnAvatarMenuChanged(
606 AvatarMenu
* avatar_menu
) {
607 if (view_mode_
== profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER
||
608 view_mode_
== profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT
) {
609 // Refresh the view with the new menu. We can't just update the local copy
610 // as this may have been triggered by a sign out action, in which case
611 // the view is being destroyed.
612 ShowView(view_mode_
, avatar_menu
);
616 void ProfileChooserView::OnRefreshTokenAvailable(
617 const std::string
& account_id
) {
618 if (view_mode_
== profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT
||
619 view_mode_
== profiles::BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT
||
620 view_mode_
== profiles::BUBBLE_VIEW_MODE_GAIA_REAUTH
) {
621 // The account management UI is only available through the
622 // --enable-account-consistency flag.
623 ShowView(switches::IsEnableAccountConsistency() ?
624 profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT
:
625 profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER
, avatar_menu_
.get());
629 void ProfileChooserView::OnRefreshTokenRevoked(const std::string
& account_id
) {
630 // Refresh the account management view when an account is removed from the
632 if (view_mode_
== profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT
)
633 ShowView(profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT
, avatar_menu_
.get());
636 void ProfileChooserView::ShowView(profiles::BubbleViewMode view_to_display
,
637 AvatarMenu
* avatar_menu
) {
638 // The account management view should only be displayed if the active profile
640 if (view_to_display
== profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT
) {
641 DCHECK(switches::IsEnableAccountConsistency());
642 const AvatarMenu::Item
& active_item
= avatar_menu
->GetItemAt(
643 avatar_menu
->GetActiveProfileIndex());
644 DCHECK(active_item
.signed_in
);
647 if (browser_
->profile()->IsSupervised() &&
648 (view_to_display
== profiles::BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT
||
649 view_to_display
== profiles::BUBBLE_VIEW_MODE_ACCOUNT_REMOVAL
)) {
650 LOG(WARNING
) << "Supervised user attempted to add/remove account";
655 RemoveAllChildViews(true);
656 view_mode_
= view_to_display
;
658 views::GridLayout
* layout
;
659 views::View
* sub_view
;
660 switch (view_mode_
) {
661 case profiles::BUBBLE_VIEW_MODE_GAIA_SIGNIN
:
662 case profiles::BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT
:
663 case profiles::BUBBLE_VIEW_MODE_GAIA_REAUTH
:
664 layout
= CreateSingleColumnLayout(this, kFixedGaiaViewWidth
);
665 sub_view
= CreateGaiaSigninView();
667 case profiles::BUBBLE_VIEW_MODE_ACCOUNT_REMOVAL
:
668 layout
= CreateSingleColumnLayout(this, kFixedAccountRemovalViewWidth
);
669 sub_view
= CreateAccountRemovalView();
671 case profiles::BUBBLE_VIEW_MODE_SWITCH_USER
:
672 layout
= CreateSingleColumnLayout(this, kFixedSwitchUserViewWidth
);
673 sub_view
= CreateSwitchUserView();
674 ProfileMetrics::LogProfileNewAvatarMenuNotYou(
675 ProfileMetrics::PROFILE_AVATAR_MENU_NOT_YOU_VIEW
);
678 layout
= CreateSingleColumnLayout(this, kFixedMenuWidth
);
679 sub_view
= CreateProfileChooserView(avatar_menu
);
681 // Clears tutorial mode for all non-profile-chooser views.
682 if (view_mode_
!= profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER
)
683 tutorial_mode_
= profiles::TUTORIAL_MODE_NONE
;
685 layout
->StartRow(1, 0);
686 layout
->AddView(sub_view
);
688 if (GetBubbleFrameView())
692 void ProfileChooserView::WindowClosing() {
693 DCHECK_EQ(profile_bubble_
, this);
694 profile_bubble_
= NULL
;
696 if (tutorial_mode_
== profiles::TUTORIAL_MODE_CONFIRM_SIGNIN
) {
697 LoginUIServiceFactory::GetForProfile(browser_
->profile())->
698 SyncConfirmationUIClosed(false /* configure_sync_first */);
702 bool ProfileChooserView::AcceleratorPressed(
703 const ui::Accelerator
& accelerator
) {
704 if (accelerator
.key_code() != ui::VKEY_DOWN
&&
705 accelerator
.key_code() != ui::VKEY_UP
)
706 return BubbleDelegateView::AcceleratorPressed(accelerator
);
707 // Move the focus up or down.
708 GetFocusManager()->AdvanceFocus(accelerator
.key_code() != ui::VKEY_DOWN
);
712 void ProfileChooserView::ButtonPressed(views::Button
* sender
,
713 const ui::Event
& event
) {
714 if (sender
== users_button_
) {
715 // If this is a guest session, close all the guest browser windows.
716 if (browser_
->profile()->IsGuestSession()) {
717 profiles::CloseGuestProfileWindows();
719 UserManager::Show(base::FilePath(),
720 profiles::USER_MANAGER_NO_TUTORIAL
,
721 profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION
);
723 PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_OPEN_USER_MANAGER
);
724 } else if (sender
== go_incognito_button_
) {
725 DCHECK(ShouldShowGoIncognito());
726 chrome::NewIncognitoWindow(browser_
);
727 } else if (sender
== lock_button_
) {
728 profiles::LockProfile(browser_
->profile());
729 PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_LOCK
);
730 } else if (sender
== auth_error_email_button_
) {
731 ShowView(profiles::BUBBLE_VIEW_MODE_GAIA_REAUTH
, avatar_menu_
.get());
732 } else if (sender
== tutorial_sync_settings_ok_button_
) {
733 LoginUIServiceFactory::GetForProfile(browser_
->profile())->
734 SyncConfirmationUIClosed(false /* configure_sync_first */);
736 ProfileMetrics::LogProfileNewAvatarMenuSignin(
737 ProfileMetrics::PROFILE_AVATAR_MENU_SIGNIN_OK
);
738 } else if (sender
== tutorial_close_button_
) {
739 DCHECK(tutorial_mode_
!= profiles::TUTORIAL_MODE_NONE
&&
740 tutorial_mode_
!= profiles::TUTORIAL_MODE_CONFIRM_SIGNIN
);
742 } else if (sender
== tutorial_see_whats_new_button_
) {
743 ProfileMetrics::LogProfileNewAvatarMenuUpgrade(
744 ProfileMetrics::PROFILE_AVATAR_MENU_UPGRADE_WHATS_NEW
);
745 UserManager::Show(base::FilePath(),
746 profiles::USER_MANAGER_TUTORIAL_OVERVIEW
,
747 profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION
);
748 } else if (sender
== remove_account_button_
) {
750 } else if (sender
== account_removal_cancel_button_
) {
751 account_id_to_remove_
.clear();
752 ShowView(profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT
, avatar_menu_
.get());
753 } else if (sender
== gaia_signin_cancel_button_
) {
754 // The account management view is only available with the
755 // --enable-account-consistency flag.
756 bool account_management_available
=
757 SigninManagerFactory::GetForProfile(browser_
->profile())->
759 switches::IsEnableAccountConsistency();
760 ShowView(account_management_available
?
761 profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT
:
762 profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER
, avatar_menu_
.get());
763 } else if (sender
== current_profile_photo_
) {
764 avatar_menu_
->EditProfile(avatar_menu_
->GetActiveProfileIndex());
765 PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_EDIT_IMAGE
);
766 } else if (sender
== signin_current_profile_link_
) {
767 ShowView(profiles::BUBBLE_VIEW_MODE_GAIA_SIGNIN
, avatar_menu_
.get());
768 } else if (sender
== add_person_button_
) {
769 ProfileMetrics::LogProfileNewAvatarMenuNotYou(
770 ProfileMetrics::PROFILE_AVATAR_MENU_NOT_YOU_ADD_PERSON
);
771 UserManager::Show(base::FilePath(),
772 profiles::USER_MANAGER_NO_TUTORIAL
,
773 profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION
);
774 } else if (sender
== disconnect_button_
) {
775 ProfileMetrics::LogProfileNewAvatarMenuNotYou(
776 ProfileMetrics::PROFILE_AVATAR_MENU_NOT_YOU_DISCONNECT
);
777 chrome::ShowSettings(browser_
);
778 } else if (sender
== switch_user_cancel_button_
) {
779 ShowView(profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER
, avatar_menu_
.get());
780 ProfileMetrics::LogProfileNewAvatarMenuNotYou(
781 ProfileMetrics::PROFILE_AVATAR_MENU_NOT_YOU_BACK
);
783 // Either one of the "other profiles", or one of the profile accounts
784 // buttons was pressed.
785 ButtonIndexes::const_iterator profile_match
=
786 open_other_profile_indexes_map_
.find(sender
);
787 if (profile_match
!= open_other_profile_indexes_map_
.end()) {
788 avatar_menu_
->SwitchToProfile(
789 profile_match
->second
,
790 ui::DispositionFromEventFlags(event
.flags()) == NEW_WINDOW
,
791 ProfileMetrics::SWITCH_PROFILE_ICON
);
793 // This was a profile accounts button.
794 AccountButtonIndexes::const_iterator account_match
=
795 delete_account_button_map_
.find(sender
);
796 if (account_match
!= delete_account_button_map_
.end()) {
797 account_id_to_remove_
= account_match
->second
;
798 ShowView(profiles::BUBBLE_VIEW_MODE_ACCOUNT_REMOVAL
,
801 account_match
= reauth_account_button_map_
.find(sender
);
802 DCHECK(account_match
!= reauth_account_button_map_
.end());
803 ShowView(profiles::BUBBLE_VIEW_MODE_GAIA_REAUTH
, avatar_menu_
.get());
809 void ProfileChooserView::RemoveAccount() {
810 DCHECK(!account_id_to_remove_
.empty());
811 MutableProfileOAuth2TokenService
* oauth2_token_service
=
812 ProfileOAuth2TokenServiceFactory::GetPlatformSpecificForProfile(
813 browser_
->profile());
814 if (oauth2_token_service
) {
815 oauth2_token_service
->RevokeCredentials(account_id_to_remove_
);
816 PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_REMOVE_ACCT
);
818 account_id_to_remove_
.clear();
820 ShowView(profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT
, avatar_menu_
.get());
823 void ProfileChooserView::LinkClicked(views::Link
* sender
, int event_flags
) {
824 if (sender
== manage_accounts_link_
) {
825 // This link can either mean show/hide the account management view,
826 // depending on which view it is displayed. ShowView() will DCHECK if
827 // the account management view is displayed for non signed-in users.
829 view_mode_
== profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT
?
830 profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER
:
831 profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT
,
833 } else if (sender
== add_account_link_
) {
834 ShowView(profiles::BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT
, avatar_menu_
.get());
835 PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_ADD_ACCT
);
836 } else if (sender
== tutorial_sync_settings_link_
) {
837 LoginUIServiceFactory::GetForProfile(browser_
->profile())->
838 SyncConfirmationUIClosed(true /* configure_sync_first */);
839 tutorial_mode_
= profiles::TUTORIAL_MODE_NONE
;
840 ProfileMetrics::LogProfileNewAvatarMenuSignin(
841 ProfileMetrics::PROFILE_AVATAR_MENU_SIGNIN_SETTINGS
);
842 } else if (sender
== tutorial_not_you_link_
) {
843 ProfileMetrics::LogProfileNewAvatarMenuUpgrade(
844 ProfileMetrics::PROFILE_AVATAR_MENU_UPGRADE_NOT_YOU
);
845 ShowView(profiles::BUBBLE_VIEW_MODE_SWITCH_USER
, avatar_menu_
.get());
847 DCHECK(sender
== tutorial_learn_more_link_
);
848 signin_ui_util::ShowSigninErrorLearnMorePage(browser_
->profile());
852 void ProfileChooserView::StyledLabelLinkClicked(
853 const gfx::Range
& range
, int event_flags
) {
854 chrome::ShowSettings(browser_
);
857 bool ProfileChooserView::HandleKeyEvent(views::Textfield
* sender
,
858 const ui::KeyEvent
& key_event
) {
859 views::Textfield
* name_textfield
=
860 current_profile_name_
->profile_name_textfield();
861 DCHECK(sender
== name_textfield
);
863 if (key_event
.key_code() == ui::VKEY_RETURN
||
864 key_event
.key_code() == ui::VKEY_TAB
) {
865 // Pressing Tab/Enter commits the new profile name, unless it's empty.
866 base::string16 new_profile_name
= name_textfield
->text();
867 base::TrimWhitespace(new_profile_name
, base::TRIM_ALL
, &new_profile_name
);
868 if (new_profile_name
.empty())
871 const AvatarMenu::Item
& active_item
= avatar_menu_
->GetItemAt(
872 avatar_menu_
->GetActiveProfileIndex());
873 Profile
* profile
= g_browser_process
->profile_manager()->GetProfile(
874 active_item
.profile_path
);
877 if (profile
->IsSupervised())
880 profiles::UpdateProfileName(profile
, new_profile_name
);
881 PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_EDIT_NAME
);
882 current_profile_name_
->ShowReadOnlyView();
888 views::View
* ProfileChooserView::CreateProfileChooserView(
889 AvatarMenu
* avatar_menu
) {
890 views::View
* view
= new views::View();
891 views::GridLayout
* layout
= CreateSingleColumnLayout(view
, kFixedMenuWidth
);
892 // Separate items into active and alternatives.
893 Indexes other_profiles
;
894 views::View
* tutorial_view
= NULL
;
895 views::View
* current_profile_view
= NULL
;
896 views::View
* current_profile_accounts
= NULL
;
897 views::View
* option_buttons_view
= NULL
;
898 for (size_t i
= 0; i
< avatar_menu
->GetNumberOfItems(); ++i
) {
899 const AvatarMenu::Item
& item
= avatar_menu
->GetItemAt(i
);
901 option_buttons_view
= CreateOptionsView(
902 item
.signed_in
&& profiles::IsLockAvailable(browser_
->profile()));
903 current_profile_view
= CreateCurrentProfileView(item
, false);
904 if (view_mode_
== profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER
) {
905 switch (tutorial_mode_
) {
906 case profiles::TUTORIAL_MODE_NONE
:
907 case profiles::TUTORIAL_MODE_WELCOME_UPGRADE
:
908 tutorial_view
= CreateWelcomeUpgradeTutorialViewIfNeeded(
909 tutorial_mode_
== profiles::TUTORIAL_MODE_WELCOME_UPGRADE
,
912 case profiles::TUTORIAL_MODE_CONFIRM_SIGNIN
:
913 tutorial_view
= CreateSigninConfirmationView();
915 case profiles::TUTORIAL_MODE_SHOW_ERROR
:
916 tutorial_view
= CreateSigninErrorView();
920 current_profile_accounts
= CreateCurrentProfileAccountsView(item
);
923 other_profiles
.push_back(i
);
928 // TODO(mlerman): update UMA stats for the new tutorial.
929 layout
->StartRow(1, 0);
930 layout
->AddView(tutorial_view
);
932 tutorial_mode_
= profiles::TUTORIAL_MODE_NONE
;
935 if (!current_profile_view
) {
936 // Guest windows don't have an active profile.
937 current_profile_view
= CreateGuestProfileView();
938 option_buttons_view
= CreateOptionsView(false);
941 layout
->StartRow(1, 0);
942 layout
->AddView(current_profile_view
);
944 if (view_mode_
!= profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER
) {
945 DCHECK(current_profile_accounts
);
946 layout
->StartRow(0, 0);
947 layout
->AddView(new views::Separator(views::Separator::HORIZONTAL
));
948 layout
->StartRow(1, 0);
949 layout
->AddView(current_profile_accounts
);
952 if (browser_
->profile()->IsSupervised()) {
953 layout
->StartRow(0, 0);
954 layout
->AddView(new views::Separator(views::Separator::HORIZONTAL
));
955 layout
->StartRow(1, 0);
956 layout
->AddView(CreateSupervisedUserDisclaimerView());
959 if (view_mode_
== profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER
) {
960 layout
->StartRow(1, 0);
961 if (switches::IsFastUserSwitching())
962 layout
->AddView(CreateOtherProfilesView(other_profiles
));
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
);
976 void ProfileChooserView::DismissTutorial() {
977 // Never shows the upgrade tutorial again if manually closed.
978 if (tutorial_mode_
== profiles::TUTORIAL_MODE_WELCOME_UPGRADE
) {
979 browser_
->profile()->GetPrefs()->SetInteger(
980 prefs::kProfileAvatarTutorialShown
,
981 signin_ui_util::kUpgradeWelcomeTutorialShowMax
+ 1);
984 tutorial_mode_
= profiles::TUTORIAL_MODE_NONE
;
985 ShowView(profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER
, avatar_menu_
.get());
988 views::View
* ProfileChooserView::CreateTutorialView(
989 profiles::TutorialMode tutorial_mode
,
990 const base::string16
& title_text
,
991 const base::string16
& content_text
,
992 const base::string16
& link_text
,
993 const base::string16
& button_text
,
996 views::LabelButton
** button
,
997 views::ImageButton
** close_button
) {
998 tutorial_mode_
= tutorial_mode
;
1000 views::View
* view
= new views::View();
1001 view
->set_background(views::Background::CreateSolidBackground(
1002 profiles::kAvatarTutorialBackgroundColor
));
1003 views::GridLayout
* layout
= CreateSingleColumnLayout(view
,
1004 kFixedMenuWidth
- 2 * views::kButtonHEdgeMarginNew
);
1005 // Creates a second column set for buttons and links.
1006 views::ColumnSet
* button_columns
= layout
->AddColumnSet(1);
1007 button_columns
->AddColumn(views::GridLayout::LEADING
,
1008 views::GridLayout::CENTER
, 0, views::GridLayout::USE_PREF
, 0, 0);
1009 button_columns
->AddPaddingColumn(
1010 1, views::kUnrelatedControlHorizontalSpacing
);
1011 button_columns
->AddColumn(views::GridLayout::TRAILING
,
1012 views::GridLayout::CENTER
, 0, views::GridLayout::USE_PREF
, 0, 0);
1013 layout
->SetInsets(views::kButtonVEdgeMarginNew
,
1014 views::kButtonHEdgeMarginNew
,
1015 views::kButtonVEdgeMarginNew
,
1016 views::kButtonHEdgeMarginNew
);
1018 // Adds title and close button if needed.
1019 views::Label
* title_label
= new views::Label(title_text
);
1020 title_label
->SetMultiLine(true);
1021 title_label
->SetHorizontalAlignment(gfx::ALIGN_LEFT
);
1022 title_label
->SetAutoColorReadabilityEnabled(false);
1023 title_label
->SetEnabledColor(SK_ColorWHITE
);
1024 title_label
->SetFontList(ui::ResourceBundle::GetSharedInstance().GetFontList(
1025 ui::ResourceBundle::MediumFont
));
1028 layout
->StartRow(1, 1);
1029 layout
->AddView(title_label
);
1030 *close_button
= new views::ImageButton(this);
1031 (*close_button
)->SetImageAlignment(views::ImageButton::ALIGN_RIGHT
,
1032 views::ImageButton::ALIGN_MIDDLE
);
1033 ui::ResourceBundle
* rb
= &ui::ResourceBundle::GetSharedInstance();
1034 (*close_button
)->SetImage(views::ImageButton::STATE_NORMAL
,
1035 rb
->GetImageSkiaNamed(IDR_CLOSE_1
));
1036 (*close_button
)->SetImage(views::ImageButton::STATE_HOVERED
,
1037 rb
->GetImageSkiaNamed(IDR_CLOSE_1_H
));
1038 (*close_button
)->SetImage(views::ImageButton::STATE_PRESSED
,
1039 rb
->GetImageSkiaNamed(IDR_CLOSE_1_P
));
1040 layout
->AddView(*close_button
);
1042 layout
->StartRow(1, 0);
1043 layout
->AddView(title_label
);
1046 // Adds body content.
1047 views::Label
* content_label
= new views::Label(content_text
);
1048 content_label
->SetMultiLine(true);
1049 content_label
->SetHorizontalAlignment(gfx::ALIGN_LEFT
);
1050 content_label
->SetAutoColorReadabilityEnabled(false);
1051 content_label
->SetEnabledColor(profiles::kAvatarTutorialContentTextColor
);
1052 layout
->StartRowWithPadding(1, 0, 0, views::kRelatedControlVerticalSpacing
);
1053 layout
->AddView(content_label
);
1055 // Adds links and buttons.
1056 bool has_button
= !button_text
.empty();
1058 *button
= new views::LabelButton(this, button_text
);
1059 (*button
)->SetHorizontalAlignment(gfx::ALIGN_CENTER
);
1060 (*button
)->SetStyle(views::Button::STYLE_BUTTON
);
1063 bool has_link
= !link_text
.empty();
1065 *link
= CreateLink(link_text
, this);
1066 (*link
)->SetHorizontalAlignment(gfx::ALIGN_LEFT
);
1067 (*link
)->SetAutoColorReadabilityEnabled(false);
1068 (*link
)->SetEnabledColor(SK_ColorWHITE
);
1073 layout
->StartRowWithPadding(
1074 1, 0, 0, views::kUnrelatedControlVerticalSpacing
);
1075 layout
->AddView(*button
);
1077 layout
->StartRowWithPadding(
1078 1, 0, 0, views::kRelatedControlVerticalSpacing
);
1079 (*link
)->SetHorizontalAlignment(gfx::ALIGN_CENTER
);
1080 layout
->AddView(*link
);
1083 DCHECK(has_link
|| has_button
);
1084 layout
->StartRowWithPadding(
1085 1, 1, 0, views::kUnrelatedControlVerticalSpacing
);
1087 layout
->AddView(*link
);
1089 layout
->SkipColumns(1);
1091 layout
->AddView(*button
);
1093 layout
->SkipColumns(1);
1099 views::View
* ProfileChooserView::CreateCurrentProfileView(
1100 const AvatarMenu::Item
& avatar_item
,
1102 views::View
* view
= new views::View();
1103 int column_width
= kFixedMenuWidth
- 2 * views::kButtonHEdgeMarginNew
;
1104 views::GridLayout
* layout
= CreateSingleColumnLayout(view
, column_width
);
1105 layout
->SetInsets(views::kButtonVEdgeMarginNew
,
1106 views::kButtonHEdgeMarginNew
,
1107 views::kUnrelatedControlVerticalSpacing
,
1108 views::kButtonHEdgeMarginNew
);
1110 // Profile icon, centered.
1111 int x_offset
= (column_width
- kLargeImageSide
) / 2;
1112 current_profile_photo_
= new EditableProfilePhoto(
1113 this, avatar_item
.icon
, !is_guest
,
1114 gfx::Rect(x_offset
, 0, kLargeImageSide
, kLargeImageSide
));
1115 SizedContainer
* profile_icon_container
=
1116 new SizedContainer(gfx::Size(column_width
, kLargeImageSide
));
1117 profile_icon_container
->AddChildView(current_profile_photo_
);
1119 ui::ResourceBundle
* rb
= &ui::ResourceBundle::GetSharedInstance();
1120 if (browser_
->profile()->IsSupervised()) {
1121 views::ImageView
* supervised_icon
= new views::ImageView();
1122 supervised_icon
->SetImage(
1123 rb
->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_SUPERVISED
));
1124 gfx::Size preferred_size
= supervised_icon
->GetPreferredSize();
1125 gfx::Rect parent_bounds
= current_profile_photo_
->bounds();
1126 supervised_icon
->SetBounds(
1127 parent_bounds
.right() - preferred_size
.width(),
1128 parent_bounds
.bottom() - preferred_size
.height(),
1129 preferred_size
.width(),
1130 preferred_size
.height());
1131 profile_icon_container
->AddChildView(supervised_icon
);
1134 layout
->StartRow(1, 0);
1135 layout
->AddView(profile_icon_container
);
1137 // Profile name, centered.
1138 bool editing_allowed
= !is_guest
&& !browser_
->profile()->IsSupervised();
1139 current_profile_name_
= new EditableProfileName(
1141 profiles::GetAvatarNameForProfile(browser_
->profile()->GetPath()),
1143 layout
->StartRowWithPadding(1, 0, 0,
1144 views::kRelatedControlSmallVerticalSpacing
);
1145 layout
->StartRow(1, 0);
1146 layout
->AddView(current_profile_name_
);
1151 // The available links depend on the type of profile that is active.
1152 if (avatar_item
.signed_in
) {
1153 layout
->StartRow(1, 0);
1154 if (switches::IsEnableAccountConsistency()) {
1155 base::string16 link_title
= l10n_util::GetStringUTF16(
1156 view_mode_
== profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER
?
1157 IDS_PROFILES_PROFILE_MANAGE_ACCOUNTS_BUTTON
:
1158 IDS_PROFILES_PROFILE_HIDE_MANAGE_ACCOUNTS_BUTTON
);
1159 manage_accounts_link_
= CreateLink(link_title
, this);
1160 manage_accounts_link_
->SetHorizontalAlignment(gfx::ALIGN_CENTER
);
1161 layout
->AddView(manage_accounts_link_
);
1163 // Add a small padding between the email button and the profile name.
1164 layout
->StartRowWithPadding(1, 0, 0, 2);
1165 // Badge the email address if there's an authentication error.
1166 if (HasAuthError(browser_
->profile())) {
1167 const gfx::ImageSkia warning_image
= *rb
->GetImageNamed(
1168 IDR_ICON_PROFILES_ACCOUNT_BUTTON_ERROR
).ToImageSkia();
1169 auth_error_email_button_
=
1170 new RightAlignedIconLabelButton(this, avatar_item
.sync_state
);
1171 auth_error_email_button_
->SetElideBehavior(gfx::ELIDE_EMAIL
);
1172 auth_error_email_button_
->SetBorder(views::Border::NullBorder());
1173 auth_error_email_button_
->SetImage(
1174 views::LabelButton::STATE_NORMAL
, warning_image
);
1175 auth_error_email_button_
->SetTextColor(
1176 views::LabelButton::STATE_NORMAL
,
1177 views::Link::GetDefaultEnabledColor());
1178 auth_error_email_button_
->SetFocusable(true);
1179 layout
->AddView(auth_error_email_button_
);
1181 views::Label
* email_label
= new views::Label(avatar_item
.sync_state
);
1182 email_label
->SetElideBehavior(gfx::ELIDE_EMAIL
);
1183 email_label
->SetEnabled(false);
1184 layout
->AddView(email_label
);
1188 SigninManagerBase
* signin_manager
= SigninManagerFactory::GetForProfile(
1189 browser_
->profile()->GetOriginalProfile());
1190 if (signin_manager
->IsSigninAllowed()) {
1191 views::Label
* promo
= new views::Label(
1192 l10n_util::GetStringUTF16(IDS_PROFILES_SIGNIN_PROMO
));
1193 promo
->SetMultiLine(true);
1194 promo
->SetHorizontalAlignment(gfx::ALIGN_LEFT
);
1195 layout
->StartRowWithPadding(1, 0, 0,
1196 views::kRelatedControlSmallVerticalSpacing
);
1197 layout
->StartRow(1, 0);
1198 layout
->AddView(promo
);
1200 signin_current_profile_link_
= new views::BlueButton(
1201 this, l10n_util::GetStringFUTF16(IDS_SYNC_START_SYNC_BUTTON_LABEL
,
1202 l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME
)));
1203 layout
->StartRowWithPadding(1, 0, 0,
1204 views::kRelatedControlVerticalSpacing
);
1205 layout
->StartRow(1, 0);
1206 layout
->AddView(signin_current_profile_link_
);
1213 views::View
* ProfileChooserView::CreateGuestProfileView() {
1214 gfx::Image guest_icon
=
1215 ui::ResourceBundle::GetSharedInstance().GetImageNamed(
1216 profiles::GetPlaceholderAvatarIconResourceID());
1217 AvatarMenu::Item
guest_avatar_item(0, 0, guest_icon
);
1218 guest_avatar_item
.active
= true;
1219 guest_avatar_item
.name
= l10n_util::GetStringUTF16(
1220 IDS_PROFILES_GUEST_PROFILE_NAME
);
1221 guest_avatar_item
.signed_in
= false;
1223 return CreateCurrentProfileView(guest_avatar_item
, true);
1226 views::View
* ProfileChooserView::CreateOtherProfilesView(
1227 const Indexes
& avatars_to_show
) {
1228 views::View
* view
= new views::View();
1229 views::GridLayout
* layout
= CreateSingleColumnLayout(view
, kFixedMenuWidth
);
1231 int num_avatars_to_show
= avatars_to_show
.size();
1232 for (int i
= 0; i
< num_avatars_to_show
; ++i
) {
1233 const size_t index
= avatars_to_show
[i
];
1234 const AvatarMenu::Item
& item
= avatar_menu_
->GetItemAt(index
);
1235 const int kSmallImageSide
= 32;
1237 gfx::Image image
= profiles::GetSizedAvatarIcon(
1238 item
.icon
, true, kSmallImageSide
, kSmallImageSide
);
1240 views::LabelButton
* button
= new BackgroundColorHoverButton(
1243 *image
.ToImageSkia());
1244 open_other_profile_indexes_map_
[button
] = index
;
1246 layout
->StartRow(1, 0);
1247 layout
->AddView(new views::Separator(views::Separator::HORIZONTAL
));
1248 layout
->StartRow(1, 0);
1249 layout
->AddView(button
);
1255 views::View
* ProfileChooserView::CreateOptionsView(bool display_lock
) {
1256 views::View
* view
= new views::View();
1257 views::GridLayout
* layout
= CreateSingleColumnLayout(view
, kFixedMenuWidth
);
1259 base::string16 text
= browser_
->profile()->IsGuestSession() ?
1260 l10n_util::GetStringUTF16(IDS_PROFILES_EXIT_GUEST
) :
1261 l10n_util::GetStringUTF16(IDS_PROFILES_SWITCH_USERS_BUTTON
);
1262 ui::ResourceBundle
* rb
= &ui::ResourceBundle::GetSharedInstance();
1263 users_button_
= new BackgroundColorHoverButton(
1266 *rb
->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_AVATAR
));
1267 layout
->StartRow(1, 0);
1268 layout
->AddView(users_button_
);
1270 if (ShouldShowGoIncognito()) {
1271 layout
->StartRow(1, 0);
1272 layout
->AddView(new views::Separator(views::Separator::HORIZONTAL
));
1274 go_incognito_button_
= new BackgroundColorHoverButton(
1276 l10n_util::GetStringUTF16(IDS_PROFILES_GO_INCOGNITO_BUTTON
),
1277 *rb
->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_INCOGNITO
));
1278 layout
->StartRow(1, 0);
1279 layout
->AddView(go_incognito_button_
);
1283 layout
->StartRow(1, 0);
1284 layout
->AddView(new views::Separator(views::Separator::HORIZONTAL
));
1286 lock_button_
= new BackgroundColorHoverButton(
1288 l10n_util::GetStringUTF16(IDS_PROFILES_PROFILE_SIGNOUT_BUTTON
),
1289 *rb
->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_LOCK
));
1290 layout
->StartRow(1, 0);
1291 layout
->AddView(lock_button_
);
1296 views::View
* ProfileChooserView::CreateSupervisedUserDisclaimerView() {
1297 views::View
* view
= new views::View();
1298 views::GridLayout
* layout
= CreateSingleColumnLayout(
1299 view
, kFixedMenuWidth
- 2 * views::kButtonHEdgeMarginNew
);
1300 layout
->SetInsets(views::kRelatedControlVerticalSpacing
,
1301 views::kButtonHEdgeMarginNew
,
1302 views::kRelatedControlVerticalSpacing
,
1303 views::kButtonHEdgeMarginNew
);
1304 views::Label
* disclaimer
= new views::Label(
1305 avatar_menu_
->GetSupervisedUserInformation());
1306 disclaimer
->SetMultiLine(true);
1307 disclaimer
->SetAllowCharacterBreak(true);
1308 disclaimer
->SetHorizontalAlignment(gfx::ALIGN_LEFT
);
1309 ui::ResourceBundle
* rb
= &ui::ResourceBundle::GetSharedInstance();
1310 disclaimer
->SetFontList(rb
->GetFontList(ui::ResourceBundle::SmallFont
));
1311 layout
->StartRow(1, 0);
1312 layout
->AddView(disclaimer
);
1317 views::View
* ProfileChooserView::CreateCurrentProfileAccountsView(
1318 const AvatarMenu::Item
& avatar_item
) {
1319 DCHECK(avatar_item
.signed_in
);
1320 views::View
* view
= new views::View();
1321 view
->set_background(views::Background::CreateSolidBackground(
1322 profiles::kAvatarBubbleAccountsBackgroundColor
));
1323 views::GridLayout
* layout
= CreateSingleColumnLayout(view
, kFixedMenuWidth
);
1325 Profile
* profile
= browser_
->profile();
1326 std::string primary_account
=
1327 SigninManagerFactory::GetForProfile(profile
)->GetAuthenticatedAccountId();
1328 DCHECK(!primary_account
.empty());
1329 std::vector
<std::string
>accounts
=
1330 profiles::GetSecondaryAccountsForProfile(profile
, primary_account
);
1332 // Get state of authentication error, if any.
1333 std::string error_account_id
= GetAuthErrorAccountId(profile
);
1335 // The primary account should always be listed first.
1336 // TODO(rogerta): we still need to further differentiate the primary account
1337 // from the others in the UI, so more work is likely required here:
1338 // crbug.com/311124.
1339 CreateAccountButton(layout
, primary_account
, true,
1340 error_account_id
== primary_account
, kFixedMenuWidth
);
1341 for (size_t i
= 0; i
< accounts
.size(); ++i
)
1342 CreateAccountButton(layout
, accounts
[i
], false,
1343 error_account_id
== accounts
[i
], kFixedMenuWidth
);
1345 if (!profile
->IsSupervised()) {
1346 layout
->AddPaddingRow(0, views::kRelatedControlVerticalSpacing
);
1348 add_account_link_
= CreateLink(l10n_util::GetStringFUTF16(
1349 IDS_PROFILES_PROFILE_ADD_ACCOUNT_BUTTON
, avatar_item
.name
), this);
1350 add_account_link_
->SetBorder(views::Border::CreateEmptyBorder(
1351 0, views::kButtonVEdgeMarginNew
,
1352 views::kRelatedControlVerticalSpacing
, 0));
1353 layout
->StartRow(1, 0);
1354 layout
->AddView(add_account_link_
);
1360 void ProfileChooserView::CreateAccountButton(views::GridLayout
* layout
,
1361 const std::string
& account_id
,
1362 bool is_primary_account
,
1363 bool reauth_required
,
1365 std::string email
= signin_ui_util::GetDisplayEmail(browser_
->profile(),
1367 ui::ResourceBundle
* rb
= &ui::ResourceBundle::GetSharedInstance();
1368 const gfx::ImageSkia
* delete_default_image
=
1369 rb
->GetImageNamed(IDR_CLOSE_1
).ToImageSkia();
1370 const int kDeleteButtonWidth
= delete_default_image
->width();
1371 const gfx::ImageSkia warning_default_image
= reauth_required
?
1372 *rb
->GetImageNamed(IDR_ICON_PROFILES_ACCOUNT_BUTTON_ERROR
).ToImageSkia() :
1374 const int kWarningButtonWidth
= reauth_required
?
1375 warning_default_image
.width() + views::kRelatedButtonHSpacing
: 0;
1376 int available_width
= width
- 2 * views::kButtonHEdgeMarginNew
1377 - kDeleteButtonWidth
- kWarningButtonWidth
;
1378 views::LabelButton
* email_button
= new BackgroundColorHoverButton(
1379 reauth_required
? this : NULL
,
1380 base::UTF8ToUTF16(email
),
1381 warning_default_image
);
1382 email_button
->SetElideBehavior(gfx::ELIDE_EMAIL
);
1383 email_button
->SetMinSize(gfx::Size(0, kButtonHeight
));
1384 email_button
->SetMaxSize(gfx::Size(available_width
, kButtonHeight
));
1385 layout
->StartRow(1, 0);
1386 layout
->AddView(email_button
);
1388 if (reauth_required
)
1389 reauth_account_button_map_
[email_button
] = account_id
;
1392 if (!browser_
->profile()->IsSupervised()) {
1393 views::ImageButton
* delete_button
= new views::ImageButton(this);
1394 delete_button
->SetImageAlignment(views::ImageButton::ALIGN_RIGHT
,
1395 views::ImageButton::ALIGN_MIDDLE
);
1396 delete_button
->SetImage(views::ImageButton::STATE_NORMAL
,
1397 delete_default_image
);
1398 delete_button
->SetImage(views::ImageButton::STATE_HOVERED
,
1399 rb
->GetImageSkiaNamed(IDR_CLOSE_1_H
));
1400 delete_button
->SetImage(views::ImageButton::STATE_PRESSED
,
1401 rb
->GetImageSkiaNamed(IDR_CLOSE_1_P
));
1402 delete_button
->SetBounds(
1403 width
- views::kButtonHEdgeMarginNew
- kDeleteButtonWidth
,
1404 0, kDeleteButtonWidth
, kButtonHeight
);
1406 email_button
->set_notify_enter_exit_on_child(true);
1407 email_button
->AddChildView(delete_button
);
1409 // Save the original email address, as the button text could be elided.
1410 delete_account_button_map_
[delete_button
] = account_id
;
1414 views::View
* ProfileChooserView::CreateGaiaSigninView() {
1418 switch (view_mode_
) {
1419 case profiles::BUBBLE_VIEW_MODE_GAIA_SIGNIN
:
1420 url
= signin::GetPromoURL(signin::SOURCE_AVATAR_BUBBLE_SIGN_IN
,
1421 false /* auto_close */,
1422 true /* is_constrained */);
1423 message_id
= IDS_PROFILES_GAIA_SIGNIN_TITLE
;
1425 case profiles::BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT
:
1426 url
= signin::GetPromoURL(signin::SOURCE_AVATAR_BUBBLE_ADD_ACCOUNT
,
1427 false /* auto_close */,
1428 true /* is_constrained */);
1429 message_id
= IDS_PROFILES_GAIA_ADD_ACCOUNT_TITLE
;
1431 case profiles::BUBBLE_VIEW_MODE_GAIA_REAUTH
: {
1432 DCHECK(HasAuthError(browser_
->profile()));
1433 url
= signin::GetReauthURL(browser_
->profile(),
1434 GetAuthErrorUsername(browser_
->profile()));
1435 message_id
= IDS_PROFILES_GAIA_REAUTH_TITLE
;
1439 NOTREACHED() << "Called with invalid mode=" << view_mode_
;
1443 // Adds Gaia signin webview
1444 Profile
* profile
= browser_
->profile();
1445 views::WebView
* web_view
= new views::WebView(profile
);
1446 web_view
->LoadInitialURL(url
);
1447 web_view
->SetPreferredSize(
1448 gfx::Size(kFixedGaiaViewWidth
, kFixedGaiaViewHeight
));
1450 TitleCard
* title_card
= new TitleCard(l10n_util::GetStringUTF16(message_id
),
1452 &gaia_signin_cancel_button_
);
1453 return TitleCard::AddPaddedTitleCard(
1454 web_view
, title_card
, kFixedGaiaViewWidth
);
1457 views::View
* ProfileChooserView::CreateAccountRemovalView() {
1458 views::View
* view
= new views::View();
1459 views::GridLayout
* layout
= CreateSingleColumnLayout(
1460 view
, kFixedAccountRemovalViewWidth
- 2 * views::kButtonHEdgeMarginNew
);
1461 layout
->SetInsets(0,
1462 views::kButtonHEdgeMarginNew
,
1463 views::kButtonVEdgeMarginNew
,
1464 views::kButtonHEdgeMarginNew
);
1466 const std::string
& primary_account
= SigninManagerFactory::GetForProfile(
1467 browser_
->profile())->GetAuthenticatedAccountId();
1468 bool is_primary_account
= primary_account
== account_id_to_remove_
;
1471 layout
->StartRowWithPadding(1, 0, 0, views::kUnrelatedControlVerticalSpacing
);
1472 ui::ResourceBundle
* rb
= &ui::ResourceBundle::GetSharedInstance();
1473 const gfx::FontList
& small_font_list
=
1474 rb
->GetFontList(ui::ResourceBundle::SmallFont
);
1476 if (is_primary_account
) {
1477 std::string email
= signin_ui_util::GetDisplayEmail(browser_
->profile(),
1478 account_id_to_remove_
);
1479 std::vector
<size_t> offsets
;
1480 const base::string16 settings_text
=
1481 l10n_util::GetStringUTF16(IDS_PROFILES_SETTINGS_LINK
);
1482 const base::string16 primary_account_removal_text
=
1483 l10n_util::GetStringFUTF16(IDS_PROFILES_PRIMARY_ACCOUNT_REMOVAL_TEXT
,
1484 base::UTF8ToUTF16(email
), settings_text
, &offsets
);
1485 views::StyledLabel
* primary_account_removal_label
=
1486 new views::StyledLabel(primary_account_removal_text
, this);
1487 primary_account_removal_label
->AddStyleRange(
1488 gfx::Range(offsets
[1], offsets
[1] + settings_text
.size()),
1489 views::StyledLabel::RangeStyleInfo::CreateForLink());
1490 primary_account_removal_label
->SetBaseFontList(small_font_list
);
1491 layout
->AddView(primary_account_removal_label
);
1493 views::Label
* content_label
= new views::Label(
1494 l10n_util::GetStringUTF16(IDS_PROFILES_ACCOUNT_REMOVAL_TEXT
));
1495 content_label
->SetMultiLine(true);
1496 content_label
->SetHorizontalAlignment(gfx::ALIGN_LEFT
);
1497 content_label
->SetFontList(small_font_list
);
1498 layout
->AddView(content_label
);
1502 if (!is_primary_account
) {
1503 remove_account_button_
= new views::BlueButton(
1504 this, l10n_util::GetStringUTF16(IDS_PROFILES_ACCOUNT_REMOVAL_BUTTON
));
1505 remove_account_button_
->SetHorizontalAlignment(
1507 layout
->StartRowWithPadding(
1508 1, 0, 0, views::kUnrelatedControlVerticalSpacing
);
1509 layout
->AddView(remove_account_button_
);
1511 layout
->AddPaddingRow(0, views::kUnrelatedControlVerticalSpacing
);
1514 TitleCard
* title_card
= new TitleCard(
1515 l10n_util::GetStringUTF16(IDS_PROFILES_ACCOUNT_REMOVAL_TITLE
),
1516 this, &account_removal_cancel_button_
);
1517 return TitleCard::AddPaddedTitleCard(view
, title_card
,
1518 kFixedAccountRemovalViewWidth
);
1521 views::View
* ProfileChooserView::CreateWelcomeUpgradeTutorialViewIfNeeded(
1522 bool tutorial_shown
, const AvatarMenu::Item
& avatar_item
) {
1523 Profile
* profile
= browser_
->profile();
1525 const int show_count
= profile
->GetPrefs()->GetInteger(
1526 prefs::kProfileAvatarTutorialShown
);
1527 // Do not show the tutorial if user has dismissed it.
1528 if (show_count
> signin_ui_util::kUpgradeWelcomeTutorialShowMax
)
1531 if (!tutorial_shown
) {
1532 if (show_count
== signin_ui_util::kUpgradeWelcomeTutorialShowMax
)
1534 profile
->GetPrefs()->SetInteger(
1535 prefs::kProfileAvatarTutorialShown
, show_count
+ 1);
1537 ProfileMetrics::LogProfileNewAvatarMenuUpgrade(
1538 ProfileMetrics::PROFILE_AVATAR_MENU_UPGRADE_VIEW
);
1540 // For local profiles, the "Not you" link doesn't make sense.
1541 base::string16 link_message
= avatar_item
.signed_in
?
1542 l10n_util::GetStringFUTF16(IDS_PROFILES_NOT_YOU
, avatar_item
.name
) :
1545 return CreateTutorialView(
1546 profiles::TUTORIAL_MODE_WELCOME_UPGRADE
,
1547 l10n_util::GetStringUTF16(
1548 IDS_PROFILES_WELCOME_UPGRADE_TUTORIAL_TITLE
),
1549 l10n_util::GetStringUTF16(
1550 IDS_PROFILES_WELCOME_UPGRADE_TUTORIAL_CONTENT_TEXT
),
1552 l10n_util::GetStringUTF16(IDS_PROFILES_TUTORIAL_WHATS_NEW_BUTTON
),
1553 true /* stack_button */,
1554 &tutorial_not_you_link_
,
1555 &tutorial_see_whats_new_button_
,
1556 &tutorial_close_button_
);
1559 views::View
* ProfileChooserView::CreateSigninConfirmationView() {
1560 ProfileMetrics::LogProfileNewAvatarMenuSignin(
1561 ProfileMetrics::PROFILE_AVATAR_MENU_SIGNIN_VIEW
);
1563 return CreateTutorialView(
1564 profiles::TUTORIAL_MODE_CONFIRM_SIGNIN
,
1565 l10n_util::GetStringUTF16(IDS_PROFILES_CONFIRM_SIGNIN_TUTORIAL_TITLE
),
1566 l10n_util::GetStringUTF16(
1567 IDS_PROFILES_CONFIRM_SIGNIN_TUTORIAL_CONTENT_TEXT
),
1568 l10n_util::GetStringUTF16(IDS_PROFILES_SYNC_SETTINGS_LINK
),
1569 l10n_util::GetStringUTF16(IDS_PROFILES_TUTORIAL_OK_BUTTON
),
1570 false /* stack_button */,
1571 &tutorial_sync_settings_link_
,
1572 &tutorial_sync_settings_ok_button_
,
1573 NULL
/* close_button*/);
1576 views::View
* ProfileChooserView::CreateSigninErrorView() {
1577 LoginUIService
* login_ui_service
=
1578 LoginUIServiceFactory::GetForProfile(browser_
->profile());
1579 base::string16
last_login_result(login_ui_service
->GetLastLoginResult());
1580 return CreateTutorialView(
1581 profiles::TUTORIAL_MODE_SHOW_ERROR
,
1582 l10n_util::GetStringUTF16(IDS_PROFILES_ERROR_TUTORIAL_TITLE
),
1584 l10n_util::GetStringUTF16(IDS_PROFILES_PROFILE_TUTORIAL_LEARN_MORE
),
1586 false /* stack_button */,
1587 &tutorial_learn_more_link_
,
1589 &tutorial_close_button_
);
1592 views::View
* ProfileChooserView::CreateSwitchUserView() {
1593 views::View
* view
= new views::View();
1594 views::GridLayout
* layout
= CreateSingleColumnLayout(
1595 view
, kFixedSwitchUserViewWidth
);
1596 views::ColumnSet
* columns
= layout
->AddColumnSet(1);
1597 columns
->AddPaddingColumn(0, views::kButtonHEdgeMarginNew
);
1599 kFixedSwitchUserViewWidth
- 2 * views::kButtonHEdgeMarginNew
;
1600 columns
->AddColumn(views::GridLayout::FILL
, views::GridLayout::FILL
, 0,
1601 views::GridLayout::FIXED
, label_width
, label_width
);
1602 columns
->AddPaddingColumn(0, views::kButtonHEdgeMarginNew
);
1605 layout
->StartRowWithPadding(1, 1, 0, views::kUnrelatedControlVerticalSpacing
);
1606 ui::ResourceBundle
* rb
= &ui::ResourceBundle::GetSharedInstance();
1607 const gfx::FontList
& small_font_list
=
1608 rb
->GetFontList(ui::ResourceBundle::SmallFont
);
1609 const AvatarMenu::Item
& avatar_item
=
1610 avatar_menu_
->GetItemAt(avatar_menu_
->GetActiveProfileIndex());
1611 views::Label
* content_label
= new views::Label(
1612 l10n_util::GetStringFUTF16(
1613 IDS_PROFILES_NOT_YOU_CONTENT_TEXT
, avatar_item
.name
));
1614 content_label
->SetMultiLine(true);
1615 content_label
->SetHorizontalAlignment(gfx::ALIGN_LEFT
);
1616 content_label
->SetFontList(small_font_list
);
1617 layout
->AddView(content_label
);
1619 // Adds "Add person" button.
1620 layout
->StartRowWithPadding(1, 0, 0, views::kUnrelatedControlVerticalSpacing
);
1621 layout
->AddView(new views::Separator(views::Separator::HORIZONTAL
));
1623 add_person_button_
= new BackgroundColorHoverButton(
1625 l10n_util::GetStringUTF16(IDS_PROFILES_ADD_PERSON_BUTTON
),
1626 *rb
->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_AVATAR
));
1627 layout
->StartRow(1, 0);
1628 layout
->AddView(add_person_button_
);
1630 // Adds "Disconnect your Google Account" button.
1631 layout
->StartRow(1, 0);
1632 layout
->AddView(new views::Separator(views::Separator::HORIZONTAL
));
1634 disconnect_button_
= new BackgroundColorHoverButton(
1636 l10n_util::GetStringUTF16(IDS_PROFILES_DISCONNECT_BUTTON
),
1637 *rb
->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_DISCONNECT
));
1638 layout
->StartRow(1, 0);
1639 layout
->AddView(disconnect_button_
);
1641 TitleCard
* title_card
= new TitleCard(
1642 l10n_util::GetStringFUTF16(IDS_PROFILES_NOT_YOU
, avatar_item
.name
),
1643 this, &switch_user_cancel_button_
);
1644 return TitleCard::AddPaddedTitleCard(view
, title_card
,
1645 kFixedSwitchUserViewWidth
);
1648 bool ProfileChooserView::ShouldShowGoIncognito() const {
1649 bool incognito_available
=
1650 IncognitoModePrefs::GetAvailability(browser_
->profile()->GetPrefs()) !=
1651 IncognitoModePrefs::DISABLED
;
1652 return incognito_available
&& !browser_
->profile()->IsGuestSession();
1655 void ProfileChooserView::PostActionPerformed(
1656 ProfileMetrics::ProfileDesktopMenu action_performed
) {
1657 ProfileMetrics::LogProfileDesktopMenu(action_performed
, gaia_service_type_
);
1658 gaia_service_type_
= signin::GAIA_SERVICE_TYPE_NONE
;