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/profile_oauth2_token_service_factory.h"
19 #include "chrome/browser/signin/signin_header_helper.h"
20 #include "chrome/browser/signin/signin_manager_factory.h"
21 #include "chrome/browser/signin/signin_promo.h"
22 #include "chrome/browser/signin/signin_ui_util.h"
23 #include "chrome/browser/ui/browser.h"
24 #include "chrome/browser/ui/browser_commands.h"
25 #include "chrome/browser/ui/browser_dialogs.h"
26 #include "chrome/browser/ui/chrome_pages.h"
27 #include "chrome/browser/ui/singleton_tabs.h"
28 #include "chrome/browser/ui/user_manager.h"
29 #include "chrome/browser/ui/views/profiles/user_manager_view.h"
30 #include "chrome/browser/ui/webui/signin/login_ui_service.h"
31 #include "chrome/browser/ui/webui/signin/login_ui_service_factory.h"
32 #include "chrome/common/pref_names.h"
33 #include "chrome/common/url_constants.h"
34 #include "chrome/grit/chromium_strings.h"
35 #include "chrome/grit/generated_resources.h"
36 #include "components/signin/core/browser/mutable_profile_oauth2_token_service.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_manager.h"
40 #include "components/signin/core/common/profile_management_switches.h"
41 #include "content/public/browser/render_widget_host_view.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/label_button_border.h"
57 #include "ui/views/controls/button/menu_button.h"
58 #include "ui/views/controls/label.h"
59 #include "ui/views/controls/link.h"
60 #include "ui/views/controls/separator.h"
61 #include "ui/views/controls/styled_label.h"
62 #include "ui/views/controls/textfield/textfield.h"
63 #include "ui/views/controls/webview/webview.h"
64 #include "ui/views/layout/grid_layout.h"
65 #include "ui/views/layout/layout_constants.h"
66 #include "ui/views/widget/widget.h"
70 // Helpers --------------------------------------------------------------------
72 const int kFixedMenuWidth
= 250;
73 const int kButtonHeight
= 32;
74 const int kFixedGaiaViewHeight
= 440;
75 const int kFixedGaiaViewWidth
= 360;
76 const int kFixedAccountRemovalViewWidth
= 280;
77 const int kFixedSwitchUserViewWidth
= 320;
78 const int kLargeImageSide
= 88;
80 const int kVerticalSpacing
= 16;
82 bool IsProfileChooser(profiles::BubbleViewMode mode
) {
83 return mode
== profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER
||
84 mode
== profiles::BUBBLE_VIEW_MODE_FAST_PROFILE_CHOOSER
;
87 // Creates a GridLayout with a single column. This ensures that all the child
88 // views added get auto-expanded to fill the full width of the bubble.
89 views::GridLayout
* CreateSingleColumnLayout(views::View
* view
, int width
) {
90 views::GridLayout
* layout
= new views::GridLayout(view
);
91 view
->SetLayoutManager(layout
);
93 views::ColumnSet
* columns
= layout
->AddColumnSet(0);
94 columns
->AddColumn(views::GridLayout::FILL
, views::GridLayout::FILL
, 0,
95 views::GridLayout::FIXED
, width
, width
);
99 views::Link
* CreateLink(const base::string16
& link_text
,
100 views::LinkListener
* listener
) {
101 views::Link
* link_button
= new views::Link(link_text
);
102 link_button
->SetHorizontalAlignment(gfx::ALIGN_LEFT
);
103 link_button
->SetUnderline(false);
104 link_button
->set_listener(listener
);
108 gfx::ImageSkia
CreateSquarePlaceholderImage(int size
) {
110 bitmap
.allocPixels(SkImageInfo::MakeA8(size
, size
));
111 bitmap
.eraseARGB(0, 0, 0, 0);
112 return gfx::ImageSkia::CreateFrom1xBitmap(bitmap
);
115 bool HasAuthError(Profile
* profile
) {
116 const SigninErrorController
* error
=
117 profiles::GetSigninErrorController(profile
);
118 return error
&& error
->HasError();
121 std::string
GetAuthErrorAccountId(Profile
* profile
) {
122 const SigninErrorController
* error
=
123 profiles::GetSigninErrorController(profile
);
125 return std::string();
127 return error
->error_account_id();
130 std::string
GetAuthErrorUsername(Profile
* profile
) {
131 const SigninErrorController
* error
=
132 profiles::GetSigninErrorController(profile
);
134 return std::string();
136 return error
->error_username();
139 // BackgroundColorHoverButton -------------------------------------------------
141 // A custom button that allows for setting a background color when hovered over.
142 class BackgroundColorHoverButton
: public views::LabelButton
{
144 BackgroundColorHoverButton(views::ButtonListener
* listener
,
145 const base::string16
& text
,
146 const gfx::ImageSkia
& icon
)
147 : views::LabelButton(listener
, text
) {
148 SetImageLabelSpacing(views::kItemLabelSpacing
);
149 SetBorder(views::Border::CreateEmptyBorder(
150 0, views::kButtonHEdgeMarginNew
, 0, views::kButtonHEdgeMarginNew
));
151 SetMinSize(gfx::Size(0,
152 kButtonHeight
+ views::kRelatedControlVerticalSpacing
));
153 SetImage(STATE_NORMAL
, icon
);
157 ~BackgroundColorHoverButton() override
{}
160 // views::LabelButton:
161 void OnPaint(gfx::Canvas
* canvas
) override
{
162 if ((state() == STATE_PRESSED
) ||
163 (state() == STATE_HOVERED
)) {
164 canvas
->DrawColor(GetNativeTheme()->GetSystemColor(
165 ui::NativeTheme::kColorId_ButtonHoverBackgroundColor
));
167 LabelButton::OnPaint(canvas
);
170 DISALLOW_COPY_AND_ASSIGN(BackgroundColorHoverButton
);
173 // SizedContainer -------------------------------------------------
175 // A simple container view that takes an explicit preferred size.
176 class SizedContainer
: public views::View
{
178 explicit SizedContainer(const gfx::Size
& preferred_size
)
179 : preferred_size_(preferred_size
) {}
181 gfx::Size
GetPreferredSize() const override
{ return preferred_size_
; }
184 gfx::Size preferred_size_
;
189 // RightAlignedIconLabelButton -------------------------------------------------
191 // A custom LabelButton that has a centered text and right aligned icon.
192 class RightAlignedIconLabelButton
: public views::LabelButton
{
194 RightAlignedIconLabelButton(views::ButtonListener
* listener
,
195 const base::string16
& text
)
196 : views::LabelButton(listener
, text
) {
200 void Layout() override
{
201 // This layout trick keeps the text left-aligned and the icon right-aligned.
202 SetHorizontalAlignment(gfx::ALIGN_RIGHT
);
203 views::LabelButton::Layout();
204 label()->SetHorizontalAlignment(gfx::ALIGN_CENTER
);
208 DISALLOW_COPY_AND_ASSIGN(RightAlignedIconLabelButton
);
211 // EditableProfilePhoto -------------------------------------------------
213 // A custom Image control that shows a "change" button when moused over.
214 class EditableProfilePhoto
: public views::LabelButton
{
216 EditableProfilePhoto(views::ButtonListener
* listener
,
217 const gfx::Image
& icon
,
218 bool is_editing_allowed
,
219 const gfx::Rect
& bounds
)
220 : views::LabelButton(listener
, base::string16()),
221 photo_overlay_(NULL
) {
222 gfx::Image image
= profiles::GetSizedAvatarIcon(
223 icon
, true, kLargeImageSide
, kLargeImageSide
);
224 SetImage(views::LabelButton::STATE_NORMAL
, *image
.ToImageSkia());
225 SetBorder(views::Border::NullBorder());
226 SetBoundsRect(bounds
);
228 // Calculate the circular mask that will be used to display the photo.
229 circular_mask_
.addCircle(SkIntToScalar(bounds
.width() / 2),
230 SkIntToScalar(bounds
.height() / 2),
231 SkIntToScalar(bounds
.width() / 2));
233 if (!is_editing_allowed
) {
238 set_notify_enter_exit_on_child(true);
240 // Photo overlay that appears when hovering over the button.
241 photo_overlay_
= new views::ImageView();
243 const SkColor kBackgroundColor
= SkColorSetARGB(65, 255, 255, 255);
244 photo_overlay_
->set_background(
245 views::Background::CreateSolidBackground(kBackgroundColor
));
246 photo_overlay_
->SetImage(*ui::ResourceBundle::GetSharedInstance().
247 GetImageSkiaNamed(IDR_ICON_PROFILES_EDIT_CAMERA
));
249 photo_overlay_
->SetSize(bounds
.size());
250 photo_overlay_
->SetVisible(false);
251 AddChildView(photo_overlay_
);
254 void OnPaint(gfx::Canvas
* canvas
) override
{
255 // Display the profile picture as a circle.
256 canvas
->ClipPath(circular_mask_
, true);
257 views::LabelButton::OnPaint(canvas
);
260 void PaintChildren(gfx::Canvas
* canvas
,
261 const views::CullSet
& cull_set
) override
{
262 // Display any children (the "change photo" overlay) as a circle.
263 canvas
->ClipPath(circular_mask_
, true);
264 View::PaintChildren(canvas
, cull_set
);
268 // views::CustomButton:
269 void StateChanged() override
{
271 (state() == STATE_PRESSED
|| state() == STATE_HOVERED
|| HasFocus());
273 photo_overlay_
->SetVisible(show_overlay
);
276 void OnFocus() override
{
277 views::LabelButton::OnFocus();
279 photo_overlay_
->SetVisible(true);
282 void OnBlur() override
{
283 views::LabelButton::OnBlur();
284 // Don't hide the overlay if it's being shown as a result of a mouseover.
285 if (photo_overlay_
&& state() != STATE_HOVERED
)
286 photo_overlay_
->SetVisible(false);
289 gfx::Path circular_mask_
;
291 // Image that is shown when hovering over the image button. Can be NULL if
292 // the photo isn't allowed to be edited (e.g. for guest profiles).
293 views::ImageView
* photo_overlay_
;
295 DISALLOW_COPY_AND_ASSIGN(EditableProfilePhoto
);
298 // EditableProfileName -------------------------------------------------
300 // A custom text control that turns into a textfield for editing when clicked.
301 class EditableProfileName
: public RightAlignedIconLabelButton
,
302 public views::ButtonListener
{
304 EditableProfileName(views::TextfieldController
* controller
,
305 const base::string16
& text
,
306 bool is_editing_allowed
)
307 : RightAlignedIconLabelButton(this, text
),
308 profile_name_textfield_(NULL
) {
309 ui::ResourceBundle
* rb
= &ui::ResourceBundle::GetSharedInstance();
310 const gfx::FontList
& medium_font_list
=
311 rb
->GetFontList(ui::ResourceBundle::MediumFont
);
312 SetFontList(medium_font_list
);
313 SetHorizontalAlignment(gfx::ALIGN_CENTER
);
315 if (!is_editing_allowed
) {
316 SetBorder(views::Border::CreateEmptyBorder(2, 0, 2, 0));
320 // Show an "edit" pencil icon when hovering over. In the default state,
321 // we need to create an empty placeholder of the correct size, so that
322 // the text doesn't jump around when the hovered icon appears.
323 gfx::ImageSkia hover_image
=
324 *rb
->GetImageSkiaNamed(IDR_ICON_PROFILES_EDIT_HOVER
);
325 SetImage(STATE_NORMAL
, CreateSquarePlaceholderImage(hover_image
.width()));
326 SetImage(STATE_HOVERED
, hover_image
);
327 SetImage(STATE_PRESSED
,
328 *rb
->GetImageSkiaNamed(IDR_ICON_PROFILES_EDIT_PRESSED
));
329 // To center the text, we need to offest it by the width of the icon we
330 // are adding and its padding. We need to also add a small top/bottom
331 // padding to account for the textfield's border.
332 const int kIconTextLabelButtonSpacing
= 5;
333 SetBorder(views::Border::CreateEmptyBorder(
334 2, hover_image
.width() + kIconTextLabelButtonSpacing
, 2, 0));
336 // Textfield that overlaps the button.
337 profile_name_textfield_
= new views::Textfield();
338 profile_name_textfield_
->set_controller(controller
);
339 profile_name_textfield_
->SetFontList(medium_font_list
);
340 profile_name_textfield_
->SetHorizontalAlignment(gfx::ALIGN_CENTER
);
342 profile_name_textfield_
->SetVisible(false);
343 AddChildView(profile_name_textfield_
);
346 views::Textfield
* profile_name_textfield() {
347 return profile_name_textfield_
;
350 // Hide the editable textfield to show the profile name button instead.
351 void ShowReadOnlyView() {
352 if (profile_name_textfield_
)
353 profile_name_textfield_
->SetVisible(false);
357 // views::ButtonListener:
358 void ButtonPressed(views::Button
* sender
, const ui::Event
& event
) override
{
359 if (profile_name_textfield_
) {
360 profile_name_textfield_
->SetVisible(true);
361 profile_name_textfield_
->SetText(GetText());
362 profile_name_textfield_
->SelectAll(false);
363 profile_name_textfield_
->RequestFocus();
367 // views::LabelButton:
368 bool OnKeyReleased(const ui::KeyEvent
& event
) override
{
369 // Override CustomButton's implementation, which presses the button when
370 // you press space and clicks it when you release space, as the space can be
371 // part of the new profile name typed in the textfield.
375 void Layout() override
{
376 if (profile_name_textfield_
)
377 profile_name_textfield_
->SetBounds(0, 0, width(), height());
378 RightAlignedIconLabelButton::Layout();
381 void OnFocus() override
{
382 RightAlignedIconLabelButton::OnFocus();
383 SetState(STATE_HOVERED
);
386 void OnBlur() override
{
387 RightAlignedIconLabelButton::OnBlur();
388 SetState(STATE_NORMAL
);
391 // Textfield that is shown when editing the profile name. Can be NULL if
392 // the profile name isn't allowed to be edited (e.g. for guest profiles).
393 views::Textfield
* profile_name_textfield_
;
395 DISALLOW_COPY_AND_ASSIGN(EditableProfileName
);
398 // A title card with one back button right aligned and one label center aligned.
399 class TitleCard
: public views::View
{
401 TitleCard(const base::string16
& message
, views::ButtonListener
* listener
,
402 views::ImageButton
** back_button
) {
403 back_button_
= new views::ImageButton(listener
);
404 back_button_
->SetImageAlignment(views::ImageButton::ALIGN_LEFT
,
405 views::ImageButton::ALIGN_MIDDLE
);
406 ui::ResourceBundle
* rb
= &ui::ResourceBundle::GetSharedInstance();
407 back_button_
->SetImage(views::ImageButton::STATE_NORMAL
,
408 rb
->GetImageSkiaNamed(IDR_BACK
));
409 back_button_
->SetImage(views::ImageButton::STATE_HOVERED
,
410 rb
->GetImageSkiaNamed(IDR_BACK_H
));
411 back_button_
->SetImage(views::ImageButton::STATE_PRESSED
,
412 rb
->GetImageSkiaNamed(IDR_BACK_P
));
413 back_button_
->SetImage(views::ImageButton::STATE_DISABLED
,
414 rb
->GetImageSkiaNamed(IDR_BACK_D
));
415 back_button_
->SetFocusable(true);
416 *back_button
= back_button_
;
418 title_label_
= new views::Label(message
);
419 title_label_
->SetHorizontalAlignment(gfx::ALIGN_CENTER
);
420 const gfx::FontList
& medium_font_list
=
421 rb
->GetFontList(ui::ResourceBundle::MediumFont
);
422 title_label_
->SetFontList(medium_font_list
);
424 AddChildView(back_button_
);
425 AddChildView(title_label_
);
428 // Creates a new view that has the |title_card| with horizontal padding at the
429 // top, an edge-to-edge separator below, and the specified |view| at the
431 static views::View
* AddPaddedTitleCard(views::View
* view
,
432 TitleCard
* title_card
,
434 views::View
* titled_view
= new views::View();
435 views::GridLayout
* layout
= new views::GridLayout(titled_view
);
436 titled_view
->SetLayoutManager(layout
);
438 // Column set 0 is a single column layout with horizontal padding at left
439 // and right, and column set 1 is a single column layout with no padding.
440 views::ColumnSet
* columns
= layout
->AddColumnSet(0);
441 columns
->AddPaddingColumn(1, views::kButtonHEdgeMarginNew
);
442 int available_width
= width
- 2 * views::kButtonHEdgeMarginNew
;
443 columns
->AddColumn(views::GridLayout::FILL
, views::GridLayout::FILL
, 0,
444 views::GridLayout::FIXED
, available_width
, available_width
);
445 columns
->AddPaddingColumn(1, views::kButtonHEdgeMarginNew
);
446 layout
->AddColumnSet(1)->AddColumn(views::GridLayout::FILL
,
447 views::GridLayout::FILL
, 0,views::GridLayout::FIXED
, width
, width
);
449 layout
->StartRowWithPadding(1, 0, 0, kVerticalSpacing
);
450 layout
->AddView(title_card
);
451 layout
->StartRowWithPadding(1, 1, 0, kVerticalSpacing
);
452 layout
->AddView(new views::Separator(views::Separator::HORIZONTAL
));
454 layout
->StartRow(1, 1);
455 layout
->AddView(view
);
461 void Layout() override
{
462 int back_button_width
= back_button_
->GetPreferredSize().width();
463 back_button_
->SetBounds(0, 0, back_button_width
, height());
464 int label_padding
= back_button_width
+ views::kButtonHEdgeMarginNew
;
465 int label_width
= width() - 2 * label_padding
;
466 DCHECK_GT(label_width
, 0);
467 title_label_
->SetBounds(label_padding
, 0, label_width
, height());
470 gfx::Size
GetPreferredSize() const override
{
471 int height
= std::max(title_label_
->GetPreferredSize().height(),
472 back_button_
->GetPreferredSize().height());
473 return gfx::Size(width(), height
);
476 views::ImageButton
* back_button_
;
477 views::Label
* title_label_
;
479 DISALLOW_COPY_AND_ASSIGN(TitleCard
);
482 // ProfileChooserView ---------------------------------------------------------
485 ProfileChooserView
* ProfileChooserView::profile_bubble_
= NULL
;
486 bool ProfileChooserView::close_on_deactivate_for_testing_
= true;
489 void ProfileChooserView::ShowBubble(
490 profiles::BubbleViewMode view_mode
,
491 profiles::TutorialMode tutorial_mode
,
492 const signin::ManageAccountsParams
& manage_accounts_params
,
493 views::View
* anchor_view
,
494 views::BubbleBorder::Arrow arrow
,
495 views::BubbleBorder::BubbleAlignment border_alignment
,
497 // Don't start creating the view if it would be an empty fast user switcher.
498 // This is the case when there is 0 or 1 profiles (the current one). It has
499 // to happen here to prevent the view system from creating an empty container.
500 if (view_mode
== profiles::BUBBLE_VIEW_MODE_FAST_PROFILE_CHOOSER
&&
501 g_browser_process
->profile_manager()->GetNumberOfProfiles() <= 1) {
506 if (tutorial_mode
!= profiles::TUTORIAL_MODE_NONE
) {
507 profile_bubble_
->tutorial_mode_
= tutorial_mode
;
508 profile_bubble_
->ShowView(view_mode
, profile_bubble_
->avatar_menu_
.get());
513 profile_bubble_
= new ProfileChooserView(anchor_view
, arrow
, browser
,
514 view_mode
, tutorial_mode
, manage_accounts_params
.service_type
);
515 views::BubbleDelegateView::CreateBubble(profile_bubble_
);
516 profile_bubble_
->set_close_on_deactivate(close_on_deactivate_for_testing_
);
517 profile_bubble_
->SetAlignment(border_alignment
);
518 profile_bubble_
->GetWidget()->Show();
519 profile_bubble_
->SetArrowPaintType(views::BubbleBorder::PAINT_NONE
);
523 bool ProfileChooserView::IsShowing() {
524 return profile_bubble_
!= NULL
;
528 void ProfileChooserView::Hide() {
530 profile_bubble_
->GetWidget()->Close();
533 ProfileChooserView::ProfileChooserView(views::View
* anchor_view
,
534 views::BubbleBorder::Arrow arrow
,
536 profiles::BubbleViewMode view_mode
,
537 profiles::TutorialMode tutorial_mode
,
538 signin::GAIAServiceType service_type
)
539 : BubbleDelegateView(anchor_view
, arrow
),
541 view_mode_(view_mode
),
542 tutorial_mode_(tutorial_mode
),
543 gaia_service_type_(service_type
) {
544 // Reset the default margins inherited from the BubbleDelegateView.
545 // Add a small bottom inset so that the bubble's rounded corners show up.
546 set_margins(gfx::Insets(0, 0, 1, 0));
547 set_background(views::Background::CreateSolidBackground(
548 GetNativeTheme()->GetSystemColor(
549 ui::NativeTheme::kColorId_DialogBackground
)));
552 avatar_menu_
.reset(new AvatarMenu(
553 &g_browser_process
->profile_manager()->GetProfileInfoCache(),
556 avatar_menu_
->RebuildMenu();
558 ProfileOAuth2TokenService
* oauth2_token_service
=
559 ProfileOAuth2TokenServiceFactory::GetForProfile(browser_
->profile());
560 if (oauth2_token_service
)
561 oauth2_token_service
->AddObserver(this);
564 ProfileChooserView::~ProfileChooserView() {
565 ProfileOAuth2TokenService
* oauth2_token_service
=
566 ProfileOAuth2TokenServiceFactory::GetForProfile(browser_
->profile());
567 if (oauth2_token_service
)
568 oauth2_token_service
->RemoveObserver(this);
571 void ProfileChooserView::ResetView() {
572 open_other_profile_indexes_map_
.clear();
573 delete_account_button_map_
.clear();
574 reauth_account_button_map_
.clear();
575 manage_accounts_link_
= NULL
;
576 signin_current_profile_link_
= NULL
;
577 auth_error_email_button_
= NULL
;
578 current_profile_photo_
= NULL
;
579 current_profile_name_
= NULL
;
580 users_button_
= NULL
;
581 go_incognito_button_
= NULL
;
583 add_account_link_
= NULL
;
584 gaia_signin_cancel_button_
= NULL
;
585 remove_account_button_
= NULL
;
586 account_removal_cancel_button_
= NULL
;
587 add_person_button_
= NULL
;
588 disconnect_button_
= NULL
;
589 switch_user_cancel_button_
= NULL
;
590 tutorial_sync_settings_ok_button_
= NULL
;
591 tutorial_close_button_
= NULL
;
592 tutorial_sync_settings_link_
= NULL
;
593 tutorial_see_whats_new_button_
= NULL
;
594 tutorial_not_you_link_
= NULL
;
595 tutorial_learn_more_link_
= NULL
;
598 void ProfileChooserView::Init() {
599 // If view mode is PROFILE_CHOOSER but there is an auth error, force
600 // ACCOUNT_MANAGEMENT mode.
601 if (IsProfileChooser(view_mode_
) &&
602 HasAuthError(browser_
->profile()) &&
603 switches::IsEnableAccountConsistency() &&
604 avatar_menu_
->GetItemAt(avatar_menu_
->GetActiveProfileIndex()).
606 view_mode_
= profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT
;
609 // The arrow keys can be used to tab between items.
610 AddAccelerator(ui::Accelerator(ui::VKEY_DOWN
, ui::EF_NONE
));
611 AddAccelerator(ui::Accelerator(ui::VKEY_UP
, ui::EF_NONE
));
613 ShowView(view_mode_
, avatar_menu_
.get());
616 void ProfileChooserView::OnAvatarMenuChanged(
617 AvatarMenu
* avatar_menu
) {
618 if (IsProfileChooser(view_mode_
) ||
619 view_mode_
== profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT
) {
620 // Refresh the view with the new menu. We can't just update the local copy
621 // as this may have been triggered by a sign out action, in which case
622 // the view is being destroyed.
623 ShowView(view_mode_
, avatar_menu
);
627 void ProfileChooserView::OnRefreshTokenAvailable(
628 const std::string
& account_id
) {
629 if (view_mode_
== profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT
||
630 view_mode_
== profiles::BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT
||
631 view_mode_
== profiles::BUBBLE_VIEW_MODE_GAIA_REAUTH
) {
632 // The account management UI is only available through the
633 // --enable-account-consistency flag.
634 ShowView(switches::IsEnableAccountConsistency() ?
635 profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT
:
636 profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER
, avatar_menu_
.get());
640 void ProfileChooserView::OnRefreshTokenRevoked(const std::string
& account_id
) {
641 // Refresh the account management view when an account is removed from the
643 if (view_mode_
== profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT
)
644 ShowView(profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT
, avatar_menu_
.get());
647 void ProfileChooserView::ShowView(profiles::BubbleViewMode view_to_display
,
648 AvatarMenu
* avatar_menu
) {
649 // The account management view should only be displayed if the active profile
651 if (view_to_display
== profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT
) {
652 DCHECK(switches::IsEnableAccountConsistency());
653 const AvatarMenu::Item
& active_item
= avatar_menu
->GetItemAt(
654 avatar_menu
->GetActiveProfileIndex());
655 DCHECK(active_item
.signed_in
);
658 if (browser_
->profile()->IsSupervised() &&
659 (view_to_display
== profiles::BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT
||
660 view_to_display
== profiles::BUBBLE_VIEW_MODE_ACCOUNT_REMOVAL
)) {
661 LOG(WARNING
) << "Supervised user attempted to add/remove account";
666 RemoveAllChildViews(true);
667 view_mode_
= view_to_display
;
669 views::GridLayout
* layout
;
670 views::View
* sub_view
;
671 switch (view_mode_
) {
672 case profiles::BUBBLE_VIEW_MODE_GAIA_SIGNIN
:
673 case profiles::BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT
:
674 case profiles::BUBBLE_VIEW_MODE_GAIA_REAUTH
:
675 layout
= CreateSingleColumnLayout(this, kFixedGaiaViewWidth
);
676 sub_view
= CreateGaiaSigninView();
678 case profiles::BUBBLE_VIEW_MODE_ACCOUNT_REMOVAL
:
679 layout
= CreateSingleColumnLayout(this, kFixedAccountRemovalViewWidth
);
680 sub_view
= CreateAccountRemovalView();
682 case profiles::BUBBLE_VIEW_MODE_SWITCH_USER
:
683 layout
= CreateSingleColumnLayout(this, kFixedSwitchUserViewWidth
);
684 sub_view
= CreateSwitchUserView();
685 ProfileMetrics::LogProfileNewAvatarMenuNotYou(
686 ProfileMetrics::PROFILE_AVATAR_MENU_NOT_YOU_VIEW
);
689 layout
= CreateSingleColumnLayout(this, kFixedMenuWidth
);
690 sub_view
= CreateProfileChooserView(avatar_menu
);
692 // Clears tutorial mode for all non-profile-chooser views.
693 if (view_mode_
!= profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER
)
694 tutorial_mode_
= profiles::TUTORIAL_MODE_NONE
;
696 layout
->StartRow(1, 0);
697 layout
->AddView(sub_view
);
699 if (GetBubbleFrameView())
703 void ProfileChooserView::WindowClosing() {
704 DCHECK_EQ(profile_bubble_
, this);
705 profile_bubble_
= NULL
;
707 if (tutorial_mode_
== profiles::TUTORIAL_MODE_CONFIRM_SIGNIN
) {
708 LoginUIServiceFactory::GetForProfile(browser_
->profile())->
709 SyncConfirmationUIClosed(false /* configure_sync_first */);
713 bool ProfileChooserView::AcceleratorPressed(
714 const ui::Accelerator
& accelerator
) {
715 if (accelerator
.key_code() != ui::VKEY_DOWN
&&
716 accelerator
.key_code() != ui::VKEY_UP
)
717 return BubbleDelegateView::AcceleratorPressed(accelerator
);
718 // Move the focus up or down.
719 GetFocusManager()->AdvanceFocus(accelerator
.key_code() != ui::VKEY_DOWN
);
723 bool ProfileChooserView::HandleContextMenu(
724 const content::ContextMenuParams
& params
) {
725 // Suppresses the context menu because some features, such as inspecting
726 // elements, are not appropriate in a bubble.
730 void ProfileChooserView::ButtonPressed(views::Button
* sender
,
731 const ui::Event
& event
) {
732 if (sender
== users_button_
) {
733 // If this is a guest session, close all the guest browser windows.
734 if (browser_
->profile()->IsGuestSession()) {
735 profiles::CloseGuestProfileWindows();
737 UserManager::Show(base::FilePath(),
738 profiles::USER_MANAGER_NO_TUTORIAL
,
739 profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION
);
741 PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_OPEN_USER_MANAGER
);
742 } else if (sender
== go_incognito_button_
) {
743 DCHECK(ShouldShowGoIncognito());
744 chrome::NewIncognitoWindow(browser_
);
745 PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_GO_INCOGNITO
);
746 } else if (sender
== lock_button_
) {
747 profiles::LockProfile(browser_
->profile());
748 PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_LOCK
);
749 } else if (sender
== auth_error_email_button_
) {
750 ShowView(profiles::BUBBLE_VIEW_MODE_GAIA_REAUTH
, avatar_menu_
.get());
751 } else if (sender
== tutorial_sync_settings_ok_button_
) {
752 LoginUIServiceFactory::GetForProfile(browser_
->profile())->
753 SyncConfirmationUIClosed(false /* configure_sync_first */);
755 ProfileMetrics::LogProfileNewAvatarMenuSignin(
756 ProfileMetrics::PROFILE_AVATAR_MENU_SIGNIN_OK
);
757 } else if (sender
== tutorial_close_button_
) {
758 DCHECK(tutorial_mode_
!= profiles::TUTORIAL_MODE_NONE
&&
759 tutorial_mode_
!= profiles::TUTORIAL_MODE_CONFIRM_SIGNIN
);
761 } else if (sender
== tutorial_see_whats_new_button_
) {
762 ProfileMetrics::LogProfileNewAvatarMenuUpgrade(
763 ProfileMetrics::PROFILE_AVATAR_MENU_UPGRADE_WHATS_NEW
);
764 UserManager::Show(base::FilePath(),
765 profiles::USER_MANAGER_TUTORIAL_OVERVIEW
,
766 profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION
);
767 } else if (sender
== remove_account_button_
) {
769 } else if (sender
== account_removal_cancel_button_
) {
770 account_id_to_remove_
.clear();
771 ShowView(profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT
, avatar_menu_
.get());
772 } else if (sender
== gaia_signin_cancel_button_
) {
773 // The account management view is only available with the
774 // --enable-account-consistency flag.
775 bool account_management_available
=
776 SigninManagerFactory::GetForProfile(browser_
->profile())->
778 switches::IsEnableAccountConsistency();
779 ShowView(account_management_available
?
780 profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT
:
781 profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER
, avatar_menu_
.get());
782 } else if (sender
== current_profile_photo_
) {
783 avatar_menu_
->EditProfile(avatar_menu_
->GetActiveProfileIndex());
784 PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_EDIT_IMAGE
);
785 } else if (sender
== signin_current_profile_link_
) {
786 ShowView(profiles::BUBBLE_VIEW_MODE_GAIA_SIGNIN
, avatar_menu_
.get());
787 } else if (sender
== add_person_button_
) {
788 ProfileMetrics::LogProfileNewAvatarMenuNotYou(
789 ProfileMetrics::PROFILE_AVATAR_MENU_NOT_YOU_ADD_PERSON
);
790 UserManager::Show(base::FilePath(),
791 profiles::USER_MANAGER_NO_TUTORIAL
,
792 profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION
);
793 } else if (sender
== disconnect_button_
) {
794 ProfileMetrics::LogProfileNewAvatarMenuNotYou(
795 ProfileMetrics::PROFILE_AVATAR_MENU_NOT_YOU_DISCONNECT
);
796 chrome::ShowSettings(browser_
);
797 } else if (sender
== switch_user_cancel_button_
) {
798 ShowView(profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER
, avatar_menu_
.get());
799 ProfileMetrics::LogProfileNewAvatarMenuNotYou(
800 ProfileMetrics::PROFILE_AVATAR_MENU_NOT_YOU_BACK
);
802 // Either one of the "other profiles", or one of the profile accounts
803 // buttons was pressed.
804 ButtonIndexes::const_iterator profile_match
=
805 open_other_profile_indexes_map_
.find(sender
);
806 if (profile_match
!= open_other_profile_indexes_map_
.end()) {
807 avatar_menu_
->SwitchToProfile(
808 profile_match
->second
,
809 ui::DispositionFromEventFlags(event
.flags()) == NEW_WINDOW
,
810 ProfileMetrics::SWITCH_PROFILE_ICON
);
812 // This was a profile accounts button.
813 AccountButtonIndexes::const_iterator account_match
=
814 delete_account_button_map_
.find(sender
);
815 if (account_match
!= delete_account_button_map_
.end()) {
816 account_id_to_remove_
= account_match
->second
;
817 ShowView(profiles::BUBBLE_VIEW_MODE_ACCOUNT_REMOVAL
,
820 account_match
= reauth_account_button_map_
.find(sender
);
821 DCHECK(account_match
!= reauth_account_button_map_
.end());
822 ShowView(profiles::BUBBLE_VIEW_MODE_GAIA_REAUTH
, avatar_menu_
.get());
828 void ProfileChooserView::RemoveAccount() {
829 DCHECK(!account_id_to_remove_
.empty());
830 MutableProfileOAuth2TokenService
* oauth2_token_service
=
831 ProfileOAuth2TokenServiceFactory::GetPlatformSpecificForProfile(
832 browser_
->profile());
833 if (oauth2_token_service
) {
834 oauth2_token_service
->RevokeCredentials(account_id_to_remove_
);
835 PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_REMOVE_ACCT
);
837 account_id_to_remove_
.clear();
839 ShowView(profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT
, avatar_menu_
.get());
842 void ProfileChooserView::LinkClicked(views::Link
* sender
, int event_flags
) {
843 if (sender
== manage_accounts_link_
) {
844 // This link can either mean show/hide the account management view,
845 // depending on which view it is displayed. ShowView() will DCHECK if
846 // the account management view is displayed for non signed-in users.
848 view_mode_
== profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT
?
849 profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER
:
850 profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT
,
852 } else if (sender
== add_account_link_
) {
853 ShowView(profiles::BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT
, avatar_menu_
.get());
854 PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_ADD_ACCT
);
855 } else if (sender
== tutorial_sync_settings_link_
) {
856 LoginUIServiceFactory::GetForProfile(browser_
->profile())->
857 SyncConfirmationUIClosed(true /* configure_sync_first */);
858 tutorial_mode_
= profiles::TUTORIAL_MODE_NONE
;
859 ProfileMetrics::LogProfileNewAvatarMenuSignin(
860 ProfileMetrics::PROFILE_AVATAR_MENU_SIGNIN_SETTINGS
);
861 } else if (sender
== tutorial_not_you_link_
) {
862 ProfileMetrics::LogProfileNewAvatarMenuUpgrade(
863 ProfileMetrics::PROFILE_AVATAR_MENU_UPGRADE_NOT_YOU
);
864 ShowView(profiles::BUBBLE_VIEW_MODE_SWITCH_USER
, avatar_menu_
.get());
866 DCHECK(sender
== tutorial_learn_more_link_
);
867 signin_ui_util::ShowSigninErrorLearnMorePage(browser_
->profile());
871 void ProfileChooserView::StyledLabelLinkClicked(
872 const gfx::Range
& range
, int event_flags
) {
873 chrome::ShowSettings(browser_
);
876 bool ProfileChooserView::HandleKeyEvent(views::Textfield
* sender
,
877 const ui::KeyEvent
& key_event
) {
878 views::Textfield
* name_textfield
=
879 current_profile_name_
->profile_name_textfield();
880 DCHECK(sender
== name_textfield
);
882 if (key_event
.key_code() == ui::VKEY_RETURN
||
883 key_event
.key_code() == ui::VKEY_TAB
) {
884 // Pressing Tab/Enter commits the new profile name, unless it's empty.
885 base::string16 new_profile_name
= name_textfield
->text();
886 base::TrimWhitespace(new_profile_name
, base::TRIM_ALL
, &new_profile_name
);
887 if (new_profile_name
.empty())
890 const AvatarMenu::Item
& active_item
= avatar_menu_
->GetItemAt(
891 avatar_menu_
->GetActiveProfileIndex());
892 Profile
* profile
= g_browser_process
->profile_manager()->GetProfile(
893 active_item
.profile_path
);
896 if (profile
->IsLegacySupervised())
899 profiles::UpdateProfileName(profile
, new_profile_name
);
900 PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_EDIT_NAME
);
901 current_profile_name_
->ShowReadOnlyView();
907 void ProfileChooserView::PopulateCompleteProfileChooserView(
908 views::GridLayout
* layout
,
909 AvatarMenu
* avatar_menu
) {
910 // Separate items into active and alternatives.
911 Indexes other_profiles
;
912 views::View
* tutorial_view
= NULL
;
913 views::View
* current_profile_view
= NULL
;
914 views::View
* current_profile_accounts
= NULL
;
915 views::View
* option_buttons_view
= NULL
;
916 for (size_t i
= 0; i
< avatar_menu
->GetNumberOfItems(); ++i
) {
917 const AvatarMenu::Item
& item
= avatar_menu
->GetItemAt(i
);
919 option_buttons_view
= CreateOptionsView(
920 item
.signed_in
&& profiles::IsLockAvailable(browser_
->profile()));
921 current_profile_view
= CreateCurrentProfileView(item
, false);
922 if (IsProfileChooser(view_mode_
)) {
923 switch (tutorial_mode_
) {
924 case profiles::TUTORIAL_MODE_NONE
:
925 case profiles::TUTORIAL_MODE_WELCOME_UPGRADE
:
926 tutorial_view
= CreateWelcomeUpgradeTutorialViewIfNeeded(
927 tutorial_mode_
== profiles::TUTORIAL_MODE_WELCOME_UPGRADE
,
930 case profiles::TUTORIAL_MODE_CONFIRM_SIGNIN
:
931 tutorial_view
= CreateSigninConfirmationView();
933 case profiles::TUTORIAL_MODE_SHOW_ERROR
:
934 tutorial_view
= CreateSigninErrorView();
938 current_profile_accounts
= CreateCurrentProfileAccountsView(item
);
941 other_profiles
.push_back(i
);
946 // TODO(mlerman): update UMA stats for the new tutorial.
947 layout
->StartRow(1, 0);
948 layout
->AddView(tutorial_view
);
950 tutorial_mode_
= profiles::TUTORIAL_MODE_NONE
;
953 if (!current_profile_view
) {
954 // Guest windows don't have an active profile.
955 current_profile_view
= CreateGuestProfileView();
956 option_buttons_view
= CreateOptionsView(false);
959 layout
->StartRow(1, 0);
960 layout
->AddView(current_profile_view
);
962 if (!IsProfileChooser(view_mode_
)) {
963 DCHECK(current_profile_accounts
);
964 layout
->StartRow(0, 0);
965 layout
->AddView(new views::Separator(views::Separator::HORIZONTAL
));
966 layout
->StartRow(1, 0);
967 layout
->AddView(current_profile_accounts
);
970 if (browser_
->profile()->IsSupervised()) {
971 layout
->StartRow(0, 0);
972 layout
->AddView(new views::Separator(views::Separator::HORIZONTAL
));
973 layout
->StartRow(1, 0);
974 layout
->AddView(CreateSupervisedUserDisclaimerView());
977 if (IsProfileChooser(view_mode_
)) {
978 layout
->StartRow(1, 0);
979 if (switches::IsFastUserSwitching()) {
980 layout
->AddView(CreateOtherProfilesView(other_profiles
));
984 layout
->StartRow(0, 0);
985 layout
->AddView(new views::Separator(views::Separator::HORIZONTAL
));
987 if (option_buttons_view
) {
988 layout
->StartRow(0, 0);
989 layout
->AddView(option_buttons_view
);
993 void ProfileChooserView::PopulateMinimalProfileChooserView(
994 views::GridLayout
* layout
,
995 AvatarMenu
* avatar_menu
) {
996 Indexes other_profiles
;
997 for (size_t i
= 0; i
< avatar_menu
->GetNumberOfItems(); ++i
) {
998 const AvatarMenu::Item
& item
= avatar_menu
->GetItemAt(i
);
1000 other_profiles
.push_back(i
);
1004 layout
->StartRow(1, 0);
1005 layout
->AddView(CreateOtherProfilesView(other_profiles
));
1008 views::View
* ProfileChooserView::CreateProfileChooserView(
1009 AvatarMenu
* avatar_menu
) {
1010 views::View
* view
= new views::View();
1011 views::GridLayout
* layout
= CreateSingleColumnLayout(view
, kFixedMenuWidth
);
1013 if (view_mode_
== profiles::BUBBLE_VIEW_MODE_FAST_PROFILE_CHOOSER
)
1014 PopulateMinimalProfileChooserView(layout
, avatar_menu
);
1016 PopulateCompleteProfileChooserView(layout
, avatar_menu
);
1021 void ProfileChooserView::DismissTutorial() {
1022 // Never shows the upgrade tutorial again if manually closed.
1023 if (tutorial_mode_
== profiles::TUTORIAL_MODE_WELCOME_UPGRADE
) {
1024 browser_
->profile()->GetPrefs()->SetInteger(
1025 prefs::kProfileAvatarTutorialShown
,
1026 signin_ui_util::kUpgradeWelcomeTutorialShowMax
+ 1);
1029 tutorial_mode_
= profiles::TUTORIAL_MODE_NONE
;
1030 ShowView(profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER
, avatar_menu_
.get());
1033 views::View
* ProfileChooserView::CreateTutorialView(
1034 profiles::TutorialMode tutorial_mode
,
1035 const base::string16
& title_text
,
1036 const base::string16
& content_text
,
1037 const base::string16
& link_text
,
1038 const base::string16
& button_text
,
1041 views::LabelButton
** button
,
1042 views::ImageButton
** close_button
) {
1043 tutorial_mode_
= tutorial_mode
;
1045 views::View
* view
= new views::View();
1046 view
->set_background(views::Background::CreateSolidBackground(
1047 profiles::kAvatarTutorialBackgroundColor
));
1048 views::GridLayout
* layout
= CreateSingleColumnLayout(view
,
1049 kFixedMenuWidth
- 2 * views::kButtonHEdgeMarginNew
);
1050 // Creates a second column set for buttons and links.
1051 views::ColumnSet
* button_columns
= layout
->AddColumnSet(1);
1052 button_columns
->AddColumn(views::GridLayout::LEADING
,
1053 views::GridLayout::CENTER
, 0, views::GridLayout::USE_PREF
, 0, 0);
1054 button_columns
->AddPaddingColumn(
1055 1, views::kUnrelatedControlHorizontalSpacing
);
1056 button_columns
->AddColumn(views::GridLayout::TRAILING
,
1057 views::GridLayout::CENTER
, 0, views::GridLayout::USE_PREF
, 0, 0);
1058 layout
->SetInsets(views::kButtonVEdgeMarginNew
,
1059 views::kButtonHEdgeMarginNew
,
1060 views::kButtonVEdgeMarginNew
,
1061 views::kButtonHEdgeMarginNew
);
1063 // Adds title and close button if needed.
1064 views::Label
* title_label
= new views::Label(title_text
);
1065 title_label
->SetMultiLine(true);
1066 title_label
->SetHorizontalAlignment(gfx::ALIGN_LEFT
);
1067 title_label
->SetAutoColorReadabilityEnabled(false);
1068 title_label
->SetEnabledColor(SK_ColorWHITE
);
1069 title_label
->SetFontList(ui::ResourceBundle::GetSharedInstance().GetFontList(
1070 ui::ResourceBundle::MediumFont
));
1073 layout
->StartRow(1, 1);
1074 layout
->AddView(title_label
);
1075 *close_button
= new views::ImageButton(this);
1076 (*close_button
)->SetImageAlignment(views::ImageButton::ALIGN_RIGHT
,
1077 views::ImageButton::ALIGN_MIDDLE
);
1078 ui::ResourceBundle
* rb
= &ui::ResourceBundle::GetSharedInstance();
1079 (*close_button
)->SetImage(views::ImageButton::STATE_NORMAL
,
1080 rb
->GetImageSkiaNamed(IDR_CLOSE_1
));
1081 (*close_button
)->SetImage(views::ImageButton::STATE_HOVERED
,
1082 rb
->GetImageSkiaNamed(IDR_CLOSE_1_H
));
1083 (*close_button
)->SetImage(views::ImageButton::STATE_PRESSED
,
1084 rb
->GetImageSkiaNamed(IDR_CLOSE_1_P
));
1085 layout
->AddView(*close_button
);
1087 layout
->StartRow(1, 0);
1088 layout
->AddView(title_label
);
1091 // Adds body content.
1092 views::Label
* content_label
= new views::Label(content_text
);
1093 content_label
->SetMultiLine(true);
1094 content_label
->SetHorizontalAlignment(gfx::ALIGN_LEFT
);
1095 content_label
->SetAutoColorReadabilityEnabled(false);
1096 content_label
->SetEnabledColor(profiles::kAvatarTutorialContentTextColor
);
1097 layout
->StartRowWithPadding(1, 0, 0, views::kRelatedControlVerticalSpacing
);
1098 layout
->AddView(content_label
);
1100 // Adds links and buttons.
1101 bool has_button
= !button_text
.empty();
1103 *button
= new views::LabelButton(this, button_text
);
1104 (*button
)->SetHorizontalAlignment(gfx::ALIGN_CENTER
);
1105 (*button
)->SetStyle(views::Button::STYLE_BUTTON
);
1108 bool has_link
= !link_text
.empty();
1110 *link
= CreateLink(link_text
, this);
1111 (*link
)->SetHorizontalAlignment(gfx::ALIGN_LEFT
);
1112 (*link
)->SetAutoColorReadabilityEnabled(false);
1113 (*link
)->SetEnabledColor(SK_ColorWHITE
);
1118 layout
->StartRowWithPadding(
1119 1, 0, 0, views::kUnrelatedControlVerticalSpacing
);
1120 layout
->AddView(*button
);
1122 layout
->StartRowWithPadding(
1123 1, 0, 0, views::kRelatedControlVerticalSpacing
);
1124 (*link
)->SetHorizontalAlignment(gfx::ALIGN_CENTER
);
1125 layout
->AddView(*link
);
1128 DCHECK(has_link
|| has_button
);
1129 layout
->StartRowWithPadding(
1130 1, 1, 0, views::kUnrelatedControlVerticalSpacing
);
1132 layout
->AddView(*link
);
1134 layout
->SkipColumns(1);
1136 layout
->AddView(*button
);
1138 layout
->SkipColumns(1);
1144 views::View
* ProfileChooserView::CreateCurrentProfileView(
1145 const AvatarMenu::Item
& avatar_item
,
1147 views::View
* view
= new views::View();
1148 int column_width
= kFixedMenuWidth
- 2 * views::kButtonHEdgeMarginNew
;
1149 views::GridLayout
* layout
= CreateSingleColumnLayout(view
, column_width
);
1150 layout
->SetInsets(views::kButtonVEdgeMarginNew
,
1151 views::kButtonHEdgeMarginNew
,
1152 views::kUnrelatedControlVerticalSpacing
,
1153 views::kButtonHEdgeMarginNew
);
1155 // Profile icon, centered.
1156 int x_offset
= (column_width
- kLargeImageSide
) / 2;
1157 current_profile_photo_
= new EditableProfilePhoto(
1158 this, avatar_item
.icon
, !is_guest
,
1159 gfx::Rect(x_offset
, 0, kLargeImageSide
, kLargeImageSide
));
1160 SizedContainer
* profile_icon_container
=
1161 new SizedContainer(gfx::Size(column_width
, kLargeImageSide
));
1162 profile_icon_container
->AddChildView(current_profile_photo_
);
1164 ui::ResourceBundle
* rb
= &ui::ResourceBundle::GetSharedInstance();
1165 if (browser_
->profile()->IsSupervised()) {
1166 views::ImageView
* supervised_icon
= new views::ImageView();
1167 int image_id
= browser_
->profile()->IsChild()
1168 ? IDR_ICON_PROFILES_MENU_CHILD
1169 : IDR_ICON_PROFILES_MENU_LEGACY_SUPERVISED
;
1170 supervised_icon
->SetImage(rb
->GetImageSkiaNamed(image_id
));
1171 gfx::Size preferred_size
= supervised_icon
->GetPreferredSize();
1172 gfx::Rect parent_bounds
= current_profile_photo_
->bounds();
1173 supervised_icon
->SetBounds(
1174 parent_bounds
.right() - preferred_size
.width(),
1175 parent_bounds
.bottom() - preferred_size
.height(),
1176 preferred_size
.width(),
1177 preferred_size
.height());
1178 profile_icon_container
->AddChildView(supervised_icon
);
1181 layout
->StartRow(1, 0);
1182 layout
->AddView(profile_icon_container
);
1184 // Profile name, centered.
1185 bool editing_allowed
= !is_guest
&&
1186 !browser_
->profile()->IsLegacySupervised();
1187 current_profile_name_
= new EditableProfileName(
1189 profiles::GetAvatarNameForProfile(browser_
->profile()->GetPath()),
1191 layout
->StartRowWithPadding(1, 0, 0,
1192 views::kRelatedControlSmallVerticalSpacing
);
1193 layout
->StartRow(1, 0);
1194 layout
->AddView(current_profile_name_
);
1199 // The available links depend on the type of profile that is active.
1200 if (avatar_item
.signed_in
) {
1201 layout
->StartRow(1, 0);
1202 if (switches::IsEnableAccountConsistency()) {
1203 base::string16 link_title
= l10n_util::GetStringUTF16(
1204 IsProfileChooser(view_mode_
) ?
1205 IDS_PROFILES_PROFILE_MANAGE_ACCOUNTS_BUTTON
:
1206 IDS_PROFILES_PROFILE_HIDE_MANAGE_ACCOUNTS_BUTTON
);
1207 manage_accounts_link_
= CreateLink(link_title
, this);
1208 manage_accounts_link_
->SetHorizontalAlignment(gfx::ALIGN_CENTER
);
1209 layout
->AddView(manage_accounts_link_
);
1211 // Badge the email address if there's an authentication error.
1212 if (HasAuthError(browser_
->profile())) {
1213 const gfx::ImageSkia warning_image
= *rb
->GetImageNamed(
1214 IDR_ICON_PROFILES_ACCOUNT_BUTTON_ERROR
).ToImageSkia();
1215 auth_error_email_button_
=
1216 new RightAlignedIconLabelButton(this, avatar_item
.sync_state
);
1217 auth_error_email_button_
->SetElideBehavior(gfx::ELIDE_EMAIL
);
1218 auth_error_email_button_
->SetImage(
1219 views::LabelButton::STATE_NORMAL
, warning_image
);
1220 auth_error_email_button_
->SetTextColor(
1221 views::LabelButton::STATE_NORMAL
,
1222 views::Link::GetDefaultEnabledColor());
1223 auth_error_email_button_
->SetFocusable(true);
1224 gfx::Insets insets
= views::LabelButtonBorder::GetDefaultInsetsForStyle(
1225 views::Button::STYLE_TEXTBUTTON
);
1226 auth_error_email_button_
->SetBorder(views::Border::CreateEmptyBorder(
1227 insets
.top(), insets
.left(), insets
.bottom(), insets
.right()));
1228 layout
->AddView(auth_error_email_button_
);
1230 // Add a small padding between the email button and the profile name.
1231 layout
->StartRowWithPadding(1, 0, 0, 2);
1232 views::Label
* email_label
= new views::Label(avatar_item
.sync_state
);
1233 email_label
->SetElideBehavior(gfx::ELIDE_EMAIL
);
1234 email_label
->SetEnabled(false);
1235 layout
->AddView(email_label
);
1239 SigninManagerBase
* signin_manager
= SigninManagerFactory::GetForProfile(
1240 browser_
->profile()->GetOriginalProfile());
1241 if (signin_manager
->IsSigninAllowed()) {
1242 views::Label
* promo
= new views::Label(
1243 l10n_util::GetStringUTF16(IDS_PROFILES_SIGNIN_PROMO
));
1244 promo
->SetMultiLine(true);
1245 promo
->SetHorizontalAlignment(gfx::ALIGN_LEFT
);
1246 layout
->StartRowWithPadding(1, 0, 0,
1247 views::kRelatedControlSmallVerticalSpacing
);
1248 layout
->StartRow(1, 0);
1249 layout
->AddView(promo
);
1251 signin_current_profile_link_
= new views::BlueButton(
1252 this, l10n_util::GetStringFUTF16(IDS_SYNC_START_SYNC_BUTTON_LABEL
,
1253 l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME
)));
1254 layout
->StartRowWithPadding(1, 0, 0,
1255 views::kRelatedControlVerticalSpacing
);
1256 layout
->StartRow(1, 0);
1257 layout
->AddView(signin_current_profile_link_
);
1264 views::View
* ProfileChooserView::CreateGuestProfileView() {
1265 gfx::Image guest_icon
=
1266 ui::ResourceBundle::GetSharedInstance().GetImageNamed(
1267 profiles::GetPlaceholderAvatarIconResourceID());
1268 AvatarMenu::Item
guest_avatar_item(0, 0, guest_icon
);
1269 guest_avatar_item
.active
= true;
1270 guest_avatar_item
.name
= l10n_util::GetStringUTF16(
1271 IDS_PROFILES_GUEST_PROFILE_NAME
);
1272 guest_avatar_item
.signed_in
= false;
1274 return CreateCurrentProfileView(guest_avatar_item
, true);
1277 views::View
* ProfileChooserView::CreateOtherProfilesView(
1278 const Indexes
& avatars_to_show
) {
1279 views::View
* view
= new views::View();
1280 views::GridLayout
* layout
= CreateSingleColumnLayout(view
, kFixedMenuWidth
);
1282 for (size_t index
: avatars_to_show
) {
1283 const AvatarMenu::Item
& item
= avatar_menu_
->GetItemAt(index
);
1284 const int kSmallImageSide
= 32;
1286 // Use the low-res, small default avatars in the fast user switcher, like
1287 // we do in the menu bar.
1288 gfx::Image item_icon
;
1290 AvatarMenu::GetImageForMenuButton(
1291 item
.profile_path
, &item_icon
, &is_rectangle
);
1293 base::string16 title
= item
.name
;
1294 if (item
.legacy_supervised
) {
1295 title
= l10n_util::GetStringFUTF16(IDS_SUPERVISED_USER_NEW_AVATAR_LABEL
,
1297 } else if (item
.child_account
) {
1298 title
= l10n_util::GetStringFUTF16(IDS_CHILD_AVATAR_LABEL
, title
);
1301 gfx::Image image
= profiles::GetSizedAvatarIcon(
1302 item_icon
, true, kSmallImageSide
, kSmallImageSide
);
1304 views::LabelButton
* button
= new BackgroundColorHoverButton(
1307 *image
.ToImageSkia());
1308 open_other_profile_indexes_map_
[button
] = index
;
1310 layout
->StartRow(1, 0);
1311 layout
->AddView(new views::Separator(views::Separator::HORIZONTAL
));
1312 layout
->StartRow(1, 0);
1313 layout
->AddView(button
);
1319 views::View
* ProfileChooserView::CreateOptionsView(bool display_lock
) {
1320 views::View
* view
= new views::View();
1321 views::GridLayout
* layout
= CreateSingleColumnLayout(view
, kFixedMenuWidth
);
1323 base::string16 text
= browser_
->profile()->IsGuestSession() ?
1324 l10n_util::GetStringUTF16(IDS_PROFILES_EXIT_GUEST
) :
1325 l10n_util::GetStringUTF16(IDS_PROFILES_SWITCH_USERS_BUTTON
);
1326 ui::ResourceBundle
* rb
= &ui::ResourceBundle::GetSharedInstance();
1327 users_button_
= new BackgroundColorHoverButton(
1330 *rb
->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_AVATAR
));
1331 layout
->StartRow(1, 0);
1332 layout
->AddView(users_button_
);
1334 if (ShouldShowGoIncognito()) {
1335 layout
->StartRow(1, 0);
1336 layout
->AddView(new views::Separator(views::Separator::HORIZONTAL
));
1338 go_incognito_button_
= new BackgroundColorHoverButton(
1340 l10n_util::GetStringUTF16(IDS_PROFILES_GO_INCOGNITO_BUTTON
),
1341 *rb
->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_INCOGNITO
));
1342 layout
->StartRow(1, 0);
1343 layout
->AddView(go_incognito_button_
);
1347 layout
->StartRow(1, 0);
1348 layout
->AddView(new views::Separator(views::Separator::HORIZONTAL
));
1350 lock_button_
= new BackgroundColorHoverButton(
1352 l10n_util::GetStringUTF16(IDS_PROFILES_PROFILE_SIGNOUT_BUTTON
),
1353 *rb
->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_LOCK
));
1354 layout
->StartRow(1, 0);
1355 layout
->AddView(lock_button_
);
1360 views::View
* ProfileChooserView::CreateSupervisedUserDisclaimerView() {
1361 views::View
* view
= new views::View();
1362 views::GridLayout
* layout
= CreateSingleColumnLayout(
1363 view
, kFixedMenuWidth
- 2 * views::kButtonHEdgeMarginNew
);
1364 layout
->SetInsets(views::kRelatedControlVerticalSpacing
,
1365 views::kButtonHEdgeMarginNew
,
1366 views::kRelatedControlVerticalSpacing
,
1367 views::kButtonHEdgeMarginNew
);
1368 views::Label
* disclaimer
= new views::Label(
1369 avatar_menu_
->GetSupervisedUserInformation());
1370 disclaimer
->SetMultiLine(true);
1371 disclaimer
->SetAllowCharacterBreak(true);
1372 disclaimer
->SetHorizontalAlignment(gfx::ALIGN_LEFT
);
1373 ui::ResourceBundle
* rb
= &ui::ResourceBundle::GetSharedInstance();
1374 disclaimer
->SetFontList(rb
->GetFontList(ui::ResourceBundle::SmallFont
));
1375 layout
->StartRow(1, 0);
1376 layout
->AddView(disclaimer
);
1381 views::View
* ProfileChooserView::CreateCurrentProfileAccountsView(
1382 const AvatarMenu::Item
& avatar_item
) {
1383 DCHECK(avatar_item
.signed_in
);
1384 views::View
* view
= new views::View();
1385 view
->set_background(views::Background::CreateSolidBackground(
1386 profiles::kAvatarBubbleAccountsBackgroundColor
));
1387 views::GridLayout
* layout
= CreateSingleColumnLayout(view
, kFixedMenuWidth
);
1389 Profile
* profile
= browser_
->profile();
1390 std::string primary_account
=
1391 SigninManagerFactory::GetForProfile(profile
)->GetAuthenticatedAccountId();
1392 DCHECK(!primary_account
.empty());
1393 std::vector
<std::string
>accounts
=
1394 profiles::GetSecondaryAccountsForProfile(profile
, primary_account
);
1396 // Get state of authentication error, if any.
1397 std::string error_account_id
= GetAuthErrorAccountId(profile
);
1399 // The primary account should always be listed first.
1400 // TODO(rogerta): we still need to further differentiate the primary account
1401 // from the others in the UI, so more work is likely required here:
1402 // crbug.com/311124.
1403 CreateAccountButton(layout
, primary_account
, true,
1404 error_account_id
== primary_account
, kFixedMenuWidth
);
1405 for (size_t i
= 0; i
< accounts
.size(); ++i
)
1406 CreateAccountButton(layout
, accounts
[i
], false,
1407 error_account_id
== accounts
[i
], kFixedMenuWidth
);
1409 if (!profile
->IsSupervised()) {
1410 layout
->AddPaddingRow(0, views::kRelatedControlVerticalSpacing
);
1412 add_account_link_
= CreateLink(l10n_util::GetStringFUTF16(
1413 IDS_PROFILES_PROFILE_ADD_ACCOUNT_BUTTON
, avatar_item
.name
), this);
1414 add_account_link_
->SetBorder(views::Border::CreateEmptyBorder(
1415 0, views::kButtonVEdgeMarginNew
,
1416 views::kRelatedControlVerticalSpacing
, 0));
1417 layout
->StartRow(1, 0);
1418 layout
->AddView(add_account_link_
);
1424 void ProfileChooserView::CreateAccountButton(views::GridLayout
* layout
,
1425 const std::string
& account_id
,
1426 bool is_primary_account
,
1427 bool reauth_required
,
1429 std::string email
= signin_ui_util::GetDisplayEmail(browser_
->profile(),
1431 ui::ResourceBundle
* rb
= &ui::ResourceBundle::GetSharedInstance();
1432 const gfx::ImageSkia
* delete_default_image
=
1433 rb
->GetImageNamed(IDR_CLOSE_1
).ToImageSkia();
1434 const int kDeleteButtonWidth
= delete_default_image
->width();
1435 const gfx::ImageSkia warning_default_image
= reauth_required
?
1436 *rb
->GetImageNamed(IDR_ICON_PROFILES_ACCOUNT_BUTTON_ERROR
).ToImageSkia() :
1438 const int kWarningButtonWidth
= reauth_required
?
1439 warning_default_image
.width() + views::kRelatedButtonHSpacing
: 0;
1440 int available_width
= width
- 2 * views::kButtonHEdgeMarginNew
1441 - kDeleteButtonWidth
- kWarningButtonWidth
;
1442 views::LabelButton
* email_button
= new BackgroundColorHoverButton(
1443 reauth_required
? this : NULL
,
1444 base::UTF8ToUTF16(email
),
1445 warning_default_image
);
1446 email_button
->SetElideBehavior(gfx::ELIDE_EMAIL
);
1447 email_button
->SetMinSize(gfx::Size(0, kButtonHeight
));
1448 email_button
->SetMaxSize(gfx::Size(available_width
, kButtonHeight
));
1449 layout
->StartRow(1, 0);
1450 layout
->AddView(email_button
);
1452 if (reauth_required
)
1453 reauth_account_button_map_
[email_button
] = account_id
;
1456 if (!browser_
->profile()->IsSupervised()) {
1457 views::ImageButton
* delete_button
= new views::ImageButton(this);
1458 delete_button
->SetImageAlignment(views::ImageButton::ALIGN_RIGHT
,
1459 views::ImageButton::ALIGN_MIDDLE
);
1460 delete_button
->SetImage(views::ImageButton::STATE_NORMAL
,
1461 delete_default_image
);
1462 delete_button
->SetImage(views::ImageButton::STATE_HOVERED
,
1463 rb
->GetImageSkiaNamed(IDR_CLOSE_1_H
));
1464 delete_button
->SetImage(views::ImageButton::STATE_PRESSED
,
1465 rb
->GetImageSkiaNamed(IDR_CLOSE_1_P
));
1466 delete_button
->SetBounds(
1467 width
- views::kButtonHEdgeMarginNew
- kDeleteButtonWidth
,
1468 0, kDeleteButtonWidth
, kButtonHeight
);
1470 email_button
->set_notify_enter_exit_on_child(true);
1471 email_button
->AddChildView(delete_button
);
1473 // Save the original email address, as the button text could be elided.
1474 delete_account_button_map_
[delete_button
] = account_id
;
1478 views::View
* ProfileChooserView::CreateGaiaSigninView() {
1482 switch (view_mode_
) {
1483 case profiles::BUBBLE_VIEW_MODE_GAIA_SIGNIN
:
1484 url
= signin::GetPromoURL(signin_metrics::SOURCE_AVATAR_BUBBLE_SIGN_IN
,
1485 false /* auto_close */,
1486 true /* is_constrained */);
1487 message_id
= IDS_PROFILES_GAIA_SIGNIN_TITLE
;
1489 case profiles::BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT
:
1490 url
= signin::GetPromoURL(
1491 signin_metrics::SOURCE_AVATAR_BUBBLE_ADD_ACCOUNT
,
1492 false /* auto_close */,
1493 true /* is_constrained */);
1494 message_id
= IDS_PROFILES_GAIA_ADD_ACCOUNT_TITLE
;
1496 case profiles::BUBBLE_VIEW_MODE_GAIA_REAUTH
: {
1497 DCHECK(HasAuthError(browser_
->profile()));
1498 url
= signin::GetReauthURL(browser_
->profile(),
1499 GetAuthErrorUsername(browser_
->profile()));
1500 message_id
= IDS_PROFILES_GAIA_REAUTH_TITLE
;
1504 NOTREACHED() << "Called with invalid mode=" << view_mode_
;
1508 // Adds Gaia signin webview
1509 Profile
* profile
= browser_
->profile();
1510 views::WebView
* web_view
= new views::WebView(profile
);
1511 web_view
->LoadInitialURL(url
);
1512 web_view
->GetWebContents()->SetDelegate(this);
1513 web_view
->SetPreferredSize(
1514 gfx::Size(kFixedGaiaViewWidth
, kFixedGaiaViewHeight
));
1515 content::RenderWidgetHostView
* rwhv
=
1516 web_view
->GetWebContents()->GetRenderWidgetHostView();
1518 rwhv
->SetBackgroundColor(profiles::kAvatarBubbleGaiaBackgroundColor
);
1519 TitleCard
* title_card
= new TitleCard(l10n_util::GetStringUTF16(message_id
),
1521 &gaia_signin_cancel_button_
);
1522 return TitleCard::AddPaddedTitleCard(
1523 web_view
, title_card
, kFixedGaiaViewWidth
);
1526 views::View
* ProfileChooserView::CreateAccountRemovalView() {
1527 views::View
* view
= new views::View();
1528 views::GridLayout
* layout
= CreateSingleColumnLayout(
1529 view
, kFixedAccountRemovalViewWidth
- 2 * views::kButtonHEdgeMarginNew
);
1530 layout
->SetInsets(0,
1531 views::kButtonHEdgeMarginNew
,
1532 views::kButtonVEdgeMarginNew
,
1533 views::kButtonHEdgeMarginNew
);
1535 const std::string
& primary_account
= SigninManagerFactory::GetForProfile(
1536 browser_
->profile())->GetAuthenticatedAccountId();
1537 bool is_primary_account
= primary_account
== account_id_to_remove_
;
1540 layout
->StartRowWithPadding(1, 0, 0, views::kUnrelatedControlVerticalSpacing
);
1541 ui::ResourceBundle
* rb
= &ui::ResourceBundle::GetSharedInstance();
1542 const gfx::FontList
& small_font_list
=
1543 rb
->GetFontList(ui::ResourceBundle::SmallFont
);
1545 if (is_primary_account
) {
1546 std::string email
= signin_ui_util::GetDisplayEmail(browser_
->profile(),
1547 account_id_to_remove_
);
1548 std::vector
<size_t> offsets
;
1549 const base::string16 settings_text
=
1550 l10n_util::GetStringUTF16(IDS_PROFILES_SETTINGS_LINK
);
1551 const base::string16 primary_account_removal_text
=
1552 l10n_util::GetStringFUTF16(IDS_PROFILES_PRIMARY_ACCOUNT_REMOVAL_TEXT
,
1553 base::UTF8ToUTF16(email
), settings_text
, &offsets
);
1554 views::StyledLabel
* primary_account_removal_label
=
1555 new views::StyledLabel(primary_account_removal_text
, this);
1556 primary_account_removal_label
->AddStyleRange(
1557 gfx::Range(offsets
[1], offsets
[1] + settings_text
.size()),
1558 views::StyledLabel::RangeStyleInfo::CreateForLink());
1559 primary_account_removal_label
->SetBaseFontList(small_font_list
);
1560 layout
->AddView(primary_account_removal_label
);
1562 views::Label
* content_label
= new views::Label(
1563 l10n_util::GetStringUTF16(IDS_PROFILES_ACCOUNT_REMOVAL_TEXT
));
1564 content_label
->SetMultiLine(true);
1565 content_label
->SetHorizontalAlignment(gfx::ALIGN_LEFT
);
1566 content_label
->SetFontList(small_font_list
);
1567 layout
->AddView(content_label
);
1571 if (!is_primary_account
) {
1572 remove_account_button_
= new views::BlueButton(
1573 this, l10n_util::GetStringUTF16(IDS_PROFILES_ACCOUNT_REMOVAL_BUTTON
));
1574 remove_account_button_
->SetHorizontalAlignment(
1576 layout
->StartRowWithPadding(
1577 1, 0, 0, views::kUnrelatedControlVerticalSpacing
);
1578 layout
->AddView(remove_account_button_
);
1580 layout
->AddPaddingRow(0, views::kUnrelatedControlVerticalSpacing
);
1583 TitleCard
* title_card
= new TitleCard(
1584 l10n_util::GetStringUTF16(IDS_PROFILES_ACCOUNT_REMOVAL_TITLE
),
1585 this, &account_removal_cancel_button_
);
1586 return TitleCard::AddPaddedTitleCard(view
, title_card
,
1587 kFixedAccountRemovalViewWidth
);
1590 views::View
* ProfileChooserView::CreateWelcomeUpgradeTutorialViewIfNeeded(
1591 bool tutorial_shown
, const AvatarMenu::Item
& avatar_item
) {
1592 Profile
* profile
= browser_
->profile();
1594 const int show_count
= profile
->GetPrefs()->GetInteger(
1595 prefs::kProfileAvatarTutorialShown
);
1596 // Do not show the tutorial if user has dismissed it.
1597 if (show_count
> signin_ui_util::kUpgradeWelcomeTutorialShowMax
)
1600 if (!tutorial_shown
) {
1601 if (show_count
== signin_ui_util::kUpgradeWelcomeTutorialShowMax
)
1603 profile
->GetPrefs()->SetInteger(
1604 prefs::kProfileAvatarTutorialShown
, show_count
+ 1);
1606 ProfileMetrics::LogProfileNewAvatarMenuUpgrade(
1607 ProfileMetrics::PROFILE_AVATAR_MENU_UPGRADE_VIEW
);
1609 // For local profiles, the "Not you" link doesn't make sense.
1610 base::string16 link_message
= avatar_item
.signed_in
?
1611 l10n_util::GetStringFUTF16(IDS_PROFILES_NOT_YOU
, avatar_item
.name
) :
1614 return CreateTutorialView(
1615 profiles::TUTORIAL_MODE_WELCOME_UPGRADE
,
1616 l10n_util::GetStringUTF16(
1617 IDS_PROFILES_WELCOME_UPGRADE_TUTORIAL_TITLE
),
1618 l10n_util::GetStringUTF16(
1619 IDS_PROFILES_WELCOME_UPGRADE_TUTORIAL_CONTENT_TEXT
),
1621 l10n_util::GetStringUTF16(IDS_PROFILES_TUTORIAL_WHATS_NEW_BUTTON
),
1622 true /* stack_button */,
1623 &tutorial_not_you_link_
,
1624 &tutorial_see_whats_new_button_
,
1625 &tutorial_close_button_
);
1628 views::View
* ProfileChooserView::CreateSigninConfirmationView() {
1629 ProfileMetrics::LogProfileNewAvatarMenuSignin(
1630 ProfileMetrics::PROFILE_AVATAR_MENU_SIGNIN_VIEW
);
1632 return CreateTutorialView(
1633 profiles::TUTORIAL_MODE_CONFIRM_SIGNIN
,
1634 l10n_util::GetStringUTF16(IDS_PROFILES_CONFIRM_SIGNIN_TUTORIAL_TITLE
),
1635 l10n_util::GetStringUTF16(
1636 IDS_PROFILES_CONFIRM_SIGNIN_TUTORIAL_CONTENT_TEXT
),
1637 l10n_util::GetStringUTF16(IDS_PROFILES_SYNC_SETTINGS_LINK
),
1638 l10n_util::GetStringUTF16(IDS_PROFILES_TUTORIAL_OK_BUTTON
),
1639 false /* stack_button */,
1640 &tutorial_sync_settings_link_
,
1641 &tutorial_sync_settings_ok_button_
,
1642 NULL
/* close_button*/);
1645 views::View
* ProfileChooserView::CreateSigninErrorView() {
1646 LoginUIService
* login_ui_service
=
1647 LoginUIServiceFactory::GetForProfile(browser_
->profile());
1648 base::string16
last_login_result(login_ui_service
->GetLastLoginResult());
1649 return CreateTutorialView(
1650 profiles::TUTORIAL_MODE_SHOW_ERROR
,
1651 l10n_util::GetStringUTF16(IDS_PROFILES_ERROR_TUTORIAL_TITLE
),
1653 l10n_util::GetStringUTF16(IDS_PROFILES_PROFILE_TUTORIAL_LEARN_MORE
),
1655 false /* stack_button */,
1656 &tutorial_learn_more_link_
,
1658 &tutorial_close_button_
);
1661 views::View
* ProfileChooserView::CreateSwitchUserView() {
1662 views::View
* view
= new views::View();
1663 views::GridLayout
* layout
= CreateSingleColumnLayout(
1664 view
, kFixedSwitchUserViewWidth
);
1665 views::ColumnSet
* columns
= layout
->AddColumnSet(1);
1666 columns
->AddPaddingColumn(0, views::kButtonHEdgeMarginNew
);
1668 kFixedSwitchUserViewWidth
- 2 * views::kButtonHEdgeMarginNew
;
1669 columns
->AddColumn(views::GridLayout::FILL
, views::GridLayout::FILL
, 0,
1670 views::GridLayout::FIXED
, label_width
, label_width
);
1671 columns
->AddPaddingColumn(0, views::kButtonHEdgeMarginNew
);
1674 layout
->StartRowWithPadding(1, 1, 0, views::kUnrelatedControlVerticalSpacing
);
1675 ui::ResourceBundle
* rb
= &ui::ResourceBundle::GetSharedInstance();
1676 const gfx::FontList
& small_font_list
=
1677 rb
->GetFontList(ui::ResourceBundle::SmallFont
);
1678 const AvatarMenu::Item
& avatar_item
=
1679 avatar_menu_
->GetItemAt(avatar_menu_
->GetActiveProfileIndex());
1680 views::Label
* content_label
= new views::Label(
1681 l10n_util::GetStringFUTF16(
1682 IDS_PROFILES_NOT_YOU_CONTENT_TEXT
, avatar_item
.name
));
1683 content_label
->SetMultiLine(true);
1684 content_label
->SetHorizontalAlignment(gfx::ALIGN_LEFT
);
1685 content_label
->SetFontList(small_font_list
);
1686 layout
->AddView(content_label
);
1688 // Adds "Add person" button.
1689 layout
->StartRowWithPadding(1, 0, 0, views::kUnrelatedControlVerticalSpacing
);
1690 layout
->AddView(new views::Separator(views::Separator::HORIZONTAL
));
1692 add_person_button_
= new BackgroundColorHoverButton(
1694 l10n_util::GetStringUTF16(IDS_PROFILES_ADD_PERSON_BUTTON
),
1695 *rb
->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_AVATAR
));
1696 layout
->StartRow(1, 0);
1697 layout
->AddView(add_person_button_
);
1699 // Adds "Disconnect your Google Account" button.
1700 layout
->StartRow(1, 0);
1701 layout
->AddView(new views::Separator(views::Separator::HORIZONTAL
));
1703 disconnect_button_
= new BackgroundColorHoverButton(
1705 l10n_util::GetStringUTF16(IDS_PROFILES_DISCONNECT_BUTTON
),
1706 *rb
->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_DISCONNECT
));
1707 layout
->StartRow(1, 0);
1708 layout
->AddView(disconnect_button_
);
1710 TitleCard
* title_card
= new TitleCard(
1711 l10n_util::GetStringFUTF16(IDS_PROFILES_NOT_YOU
, avatar_item
.name
),
1712 this, &switch_user_cancel_button_
);
1713 return TitleCard::AddPaddedTitleCard(view
, title_card
,
1714 kFixedSwitchUserViewWidth
);
1717 bool ProfileChooserView::ShouldShowGoIncognito() const {
1718 bool incognito_available
=
1719 IncognitoModePrefs::GetAvailability(browser_
->profile()->GetPrefs()) !=
1720 IncognitoModePrefs::DISABLED
;
1721 return incognito_available
&& !browser_
->profile()->IsGuestSession();
1724 void ProfileChooserView::PostActionPerformed(
1725 ProfileMetrics::ProfileDesktopMenu action_performed
) {
1726 ProfileMetrics::LogProfileDesktopMenu(action_performed
, gaia_service_type_
);
1727 gaia_service_type_
= signin::GAIA_SERVICE_TYPE_NONE
;