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