1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/ui/views/profiles/profile_chooser_view.h"
7 #include "base/prefs/pref_service.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "chrome/browser/browser_process.h"
10 #include "chrome/browser/lifetime/application_lifetime.h"
11 #include "chrome/browser/prefs/incognito_mode_prefs.h"
12 #include "chrome/browser/profiles/profile_avatar_icon_util.h"
13 #include "chrome/browser/profiles/profile_info_cache.h"
14 #include "chrome/browser/profiles/profile_manager.h"
15 #include "chrome/browser/profiles/profile_metrics.h"
16 #include "chrome/browser/profiles/profile_window.h"
17 #include "chrome/browser/profiles/profiles_state.h"
18 #include "chrome/browser/signin/chrome_signin_helper.h"
19 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
20 #include "chrome/browser/signin/signin_error_controller_factory.h"
21 #include "chrome/browser/signin/signin_manager_factory.h"
22 #include "chrome/browser/signin/signin_promo.h"
23 #include "chrome/browser/signin/signin_ui_util.h"
24 #include "chrome/browser/ui/browser.h"
25 #include "chrome/browser/ui/browser_commands.h"
26 #include "chrome/browser/ui/browser_dialogs.h"
27 #include "chrome/browser/ui/chrome_pages.h"
28 #include "chrome/browser/ui/singleton_tabs.h"
29 #include "chrome/browser/ui/user_manager.h"
30 #include "chrome/browser/ui/views/profiles/user_manager_view.h"
31 #include "chrome/browser/ui/webui/signin/login_ui_service.h"
32 #include "chrome/browser/ui/webui/signin/login_ui_service_factory.h"
33 #include "chrome/common/pref_names.h"
34 #include "chrome/common/url_constants.h"
35 #include "chrome/grit/chromium_strings.h"
36 #include "chrome/grit/generated_resources.h"
37 #include "components/signin/core/browser/profile_oauth2_token_service.h"
38 #include "components/signin/core/browser/signin_error_controller.h"
39 #include "components/signin/core/browser/signin_header_helper.h"
40 #include "components/signin/core/browser/signin_manager.h"
41 #include "components/signin/core/common/profile_management_switches.h"
42 #include "content/public/browser/render_widget_host_view.h"
43 #include "grit/theme_resources.h"
44 #include "third_party/skia/include/core/SkColor.h"
45 #include "ui/base/l10n/l10n_util.h"
46 #include "ui/base/resource/resource_bundle.h"
47 #include "ui/compositor/clip_transform_recorder.h"
48 #include "ui/gfx/canvas.h"
49 #include "ui/gfx/image/canvas_image_source.h"
50 #include "ui/gfx/image/image.h"
51 #include "ui/gfx/image/image_skia.h"
52 #include "ui/gfx/paint_vector_icon.h"
53 #include "ui/gfx/path.h"
54 #include "ui/gfx/skia_util.h"
55 #include "ui/gfx/text_elider.h"
56 #include "ui/gfx/vector_icons_public.h"
57 #include "ui/native_theme/common_theme.h"
58 #include "ui/native_theme/native_theme.h"
59 #include "ui/views/controls/button/blue_button.h"
60 #include "ui/views/controls/button/image_button.h"
61 #include "ui/views/controls/button/label_button.h"
62 #include "ui/views/controls/button/label_button_border.h"
63 #include "ui/views/controls/button/menu_button.h"
64 #include "ui/views/controls/label.h"
65 #include "ui/views/controls/link.h"
66 #include "ui/views/controls/separator.h"
67 #include "ui/views/controls/styled_label.h"
68 #include "ui/views/controls/textfield/textfield.h"
69 #include "ui/views/controls/webview/webview.h"
70 #include "ui/views/layout/grid_layout.h"
71 #include "ui/views/layout/layout_constants.h"
72 #include "ui/views/widget/widget.h"
76 // Helpers --------------------------------------------------------------------
78 const int kFixedMenuWidth
= 250;
79 const int kButtonHeight
= 32;
80 const int kFixedGaiaViewHeight
= 440;
81 const int kFixedGaiaViewWidth
= 360;
82 const int kFixedAccountRemovalViewWidth
= 280;
83 const int kFixedSwitchUserViewWidth
= 320;
84 const int kLargeImageSide
= 88;
86 const int kVerticalSpacing
= 16;
88 bool IsProfileChooser(profiles::BubbleViewMode mode
) {
89 return mode
== profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER
||
90 mode
== profiles::BUBBLE_VIEW_MODE_FAST_PROFILE_CHOOSER
;
93 // Creates a GridLayout with a single column. This ensures that all the child
94 // views added get auto-expanded to fill the full width of the bubble.
95 views::GridLayout
* CreateSingleColumnLayout(views::View
* view
, int width
) {
96 views::GridLayout
* layout
= new views::GridLayout(view
);
97 view
->SetLayoutManager(layout
);
99 views::ColumnSet
* columns
= layout
->AddColumnSet(0);
100 columns
->AddColumn(views::GridLayout::FILL
, views::GridLayout::FILL
, 0,
101 views::GridLayout::FIXED
, width
, width
);
105 views::Link
* CreateLink(const base::string16
& link_text
,
106 views::LinkListener
* listener
) {
107 views::Link
* link_button
= new views::Link(link_text
);
108 link_button
->SetHorizontalAlignment(gfx::ALIGN_LEFT
);
109 link_button
->SetUnderline(false);
110 link_button
->set_listener(listener
);
114 gfx::ImageSkia
CreateSquarePlaceholderImage(int size
) {
116 bitmap
.allocPixels(SkImageInfo::MakeA8(size
, size
));
117 bitmap
.eraseARGB(0, 0, 0, 0);
118 return gfx::ImageSkia::CreateFrom1xBitmap(bitmap
);
121 bool HasAuthError(Profile
* profile
) {
122 const SigninErrorController
* error
=
123 SigninErrorControllerFactory::GetForProfile(profile
);
124 return error
&& error
->HasError();
127 std::string
GetAuthErrorAccountId(Profile
* profile
) {
128 const SigninErrorController
* error
=
129 SigninErrorControllerFactory::GetForProfile(profile
);
131 return std::string();
133 return error
->error_account_id();
136 // BackgroundColorHoverButton -------------------------------------------------
138 // A custom button that allows for setting a background color when hovered over.
139 class BackgroundColorHoverButton
: public views::LabelButton
{
141 BackgroundColorHoverButton(views::ButtonListener
* listener
,
142 const base::string16
& text
,
143 const gfx::ImageSkia
& icon
)
144 : views::LabelButton(listener
, text
) {
145 SetImageLabelSpacing(views::kItemLabelSpacing
);
146 SetBorder(views::Border::CreateEmptyBorder(
147 0, views::kButtonHEdgeMarginNew
, 0, views::kButtonHEdgeMarginNew
));
148 SetMinSize(gfx::Size(0,
149 kButtonHeight
+ views::kRelatedControlVerticalSpacing
));
150 SetImage(STATE_NORMAL
, icon
);
154 ~BackgroundColorHoverButton() override
{}
157 // views::LabelButton:
158 void OnPaint(gfx::Canvas
* canvas
) override
{
159 if ((state() == STATE_PRESSED
) ||
160 (state() == STATE_HOVERED
)) {
161 canvas
->DrawColor(GetNativeTheme()->GetSystemColor(
162 ui::NativeTheme::kColorId_ButtonHoverBackgroundColor
));
164 LabelButton::OnPaint(canvas
);
167 DISALLOW_COPY_AND_ASSIGN(BackgroundColorHoverButton
);
170 // SizedContainer -------------------------------------------------
172 // A simple container view that takes an explicit preferred size.
173 class SizedContainer
: public views::View
{
175 explicit SizedContainer(const gfx::Size
& preferred_size
)
176 : preferred_size_(preferred_size
) {}
178 gfx::Size
GetPreferredSize() const override
{ return preferred_size_
; }
181 gfx::Size preferred_size_
;
186 // RightAlignedIconLabelButton -------------------------------------------------
188 // A custom LabelButton that has a centered text and right aligned icon.
189 class RightAlignedIconLabelButton
: public views::LabelButton
{
191 RightAlignedIconLabelButton(views::ButtonListener
* listener
,
192 const base::string16
& text
)
193 : views::LabelButton(listener
, text
) {
197 void Layout() override
{
198 // This layout trick keeps the text left-aligned and the icon right-aligned.
199 SetHorizontalAlignment(gfx::ALIGN_RIGHT
);
200 views::LabelButton::Layout();
201 label()->SetHorizontalAlignment(gfx::ALIGN_CENTER
);
205 DISALLOW_COPY_AND_ASSIGN(RightAlignedIconLabelButton
);
208 // EditableProfilePhoto -------------------------------------------------
210 // A custom Image control that shows a "change" button when moused over.
211 class EditableProfilePhoto
: public views::LabelButton
{
213 EditableProfilePhoto(views::ButtonListener
* listener
,
214 const gfx::Image
& icon
,
215 bool is_editing_allowed
,
216 const gfx::Rect
& bounds
)
217 : views::LabelButton(listener
, base::string16()),
218 photo_overlay_(NULL
) {
219 gfx::Image image
= profiles::GetSizedAvatarIcon(
220 icon
, true, kLargeImageSide
, kLargeImageSide
);
221 SetImage(views::LabelButton::STATE_NORMAL
, *image
.ToImageSkia());
222 SetBorder(views::Border::NullBorder());
223 SetBoundsRect(bounds
);
225 // Calculate the circular mask that will be used to display the photo.
226 circular_mask_
.addCircle(SkIntToScalar(bounds
.width() / 2),
227 SkIntToScalar(bounds
.height() / 2),
228 SkIntToScalar(bounds
.width() / 2));
230 if (!is_editing_allowed
) {
235 set_notify_enter_exit_on_child(true);
237 // Photo overlay that appears when hovering over the button.
238 photo_overlay_
= new views::ImageView();
240 const SkColor kBackgroundColor
= SkColorSetARGB(65, 255, 255, 255);
241 photo_overlay_
->set_background(
242 views::Background::CreateSolidBackground(kBackgroundColor
));
243 photo_overlay_
->SetImage(gfx::CreateVectorIcon(
244 gfx::VectorIconId::PHOTO_CAMERA
, 48u, SkColorSetRGB(0x33, 0x33, 0x33)));
246 photo_overlay_
->SetSize(bounds
.size());
247 photo_overlay_
->SetVisible(false);
248 AddChildView(photo_overlay_
);
251 void OnPaint(gfx::Canvas
* canvas
) override
{
252 // Display the profile picture as a circle.
253 canvas
->ClipPath(circular_mask_
, true);
254 views::LabelButton::OnPaint(canvas
);
257 void PaintChildren(const ui::PaintContext
& context
) override
{
258 // Display any children (the "change photo" overlay) as a circle.
259 ui::ClipTransformRecorder
clip_transform_recorder(context
);
260 clip_transform_recorder
.ClipPathWithAntiAliasing(circular_mask_
);
261 View::PaintChildren(context
);
265 // views::CustomButton:
266 void StateChanged() override
{
268 (state() == STATE_PRESSED
|| state() == STATE_HOVERED
|| HasFocus());
270 photo_overlay_
->SetVisible(show_overlay
);
273 void OnFocus() override
{
274 views::LabelButton::OnFocus();
276 photo_overlay_
->SetVisible(true);
279 void OnBlur() override
{
280 views::LabelButton::OnBlur();
281 // Don't hide the overlay if it's being shown as a result of a mouseover.
282 if (photo_overlay_
&& state() != STATE_HOVERED
)
283 photo_overlay_
->SetVisible(false);
286 gfx::Path circular_mask_
;
288 // Image that is shown when hovering over the image button. Can be NULL if
289 // the photo isn't allowed to be edited (e.g. for guest profiles).
290 views::ImageView
* photo_overlay_
;
292 DISALLOW_COPY_AND_ASSIGN(EditableProfilePhoto
);
295 // EditableProfileName -------------------------------------------------
297 // A custom text control that turns into a textfield for editing when clicked.
298 class EditableProfileName
: public RightAlignedIconLabelButton
,
299 public views::ButtonListener
{
301 EditableProfileName(views::TextfieldController
* controller
,
302 const base::string16
& text
,
303 bool is_editing_allowed
)
304 : RightAlignedIconLabelButton(this, text
),
305 profile_name_textfield_(NULL
) {
306 ui::ResourceBundle
* rb
= &ui::ResourceBundle::GetSharedInstance();
307 const gfx::FontList
& medium_font_list
=
308 rb
->GetFontList(ui::ResourceBundle::MediumFont
);
309 SetFontList(medium_font_list
);
310 SetHorizontalAlignment(gfx::ALIGN_CENTER
);
312 if (!is_editing_allowed
) {
313 SetBorder(views::Border::CreateEmptyBorder(2, 0, 2, 0));
317 // Show an "edit" pencil icon when hovering over. In the default state,
318 // we need to create an empty placeholder of the correct size, so that
319 // the text doesn't jump around when the hovered icon appears.
320 // TODO(estade): revisit colors and press effect.
321 const int kIconSize
= 16;
322 SetImage(STATE_NORMAL
, CreateSquarePlaceholderImage(kIconSize
));
323 SetImage(STATE_HOVERED
,
324 gfx::CreateVectorIcon(gfx::VectorIconId::MODE_EDIT
, kIconSize
,
325 SkColorSetRGB(0x33, 0x33, 0x33)));
326 SetImage(STATE_PRESSED
,
327 gfx::CreateVectorIcon(gfx::VectorIconId::MODE_EDIT
, kIconSize
,
328 SkColorSetRGB(0x20, 0x20, 0x20)));
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, kIconSize
+ 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 // ProfileBadge --------------------------------------------------------
484 const size_t kProfileBadgeSize
= 30;
485 const size_t kProfileBadgeWhitePadding
= 2;
487 // Draws a white circle, then a light blue circle, then a dark blue icon.
488 class ProfileBadge
: public gfx::CanvasImageSource
{
490 ProfileBadge(gfx::VectorIconId id
, size_t icon_size
)
491 : CanvasImageSource(gfx::Size(kProfileBadgeSize
, kProfileBadgeSize
),
494 icon_size_(icon_size
) {}
496 ~ProfileBadge() override
{}
498 // CanvasImageSource:
499 void Draw(gfx::Canvas
* canvas
) override
{
500 const SkISize size
= canvas
->sk_canvas()->getDeviceSize();
501 gfx::Rect
bounds(0, 0, size
.width(), size
.height());
504 paint
.setAntiAlias(true);
505 paint
.setColor(SK_ColorWHITE
);
506 canvas
->DrawCircle(bounds
.CenterPoint(), size
.width() / 2, paint
);
508 paint
.setColor(SkColorSetRGB(0xAF, 0xD9, 0xFC));
509 canvas
->DrawCircle(bounds
.CenterPoint(),
510 size
.width() / 2 - kProfileBadgeWhitePadding
, paint
);
512 int offset
= (kProfileBadgeSize
- icon_size_
) / 2;
513 canvas
->Translate(gfx::Vector2d(offset
, offset
));
514 gfx::PaintVectorIcon(canvas
, id_
, icon_size_
, SkColorSetRGB(0, 0x66, 0xff));
518 const gfx::VectorIconId id_
;
519 const size_t icon_size_
;
521 DISALLOW_COPY_AND_ASSIGN(ProfileBadge
);
524 gfx::ImageSkia
CreateBadgeForProfile(Profile
* profile
) {
525 ProfileBadge
* badge
=
527 ? new ProfileBadge(gfx::VectorIconId::ACCOUNT_CHILD_INVERT
, 26)
528 : new ProfileBadge(gfx::VectorIconId::SUPERVISOR_ACCOUNT
, 20);
530 return gfx::ImageSkia(badge
, badge
->size());
533 // ProfileChooserView ---------------------------------------------------------
536 ProfileChooserView
* ProfileChooserView::profile_bubble_
= NULL
;
537 bool ProfileChooserView::close_on_deactivate_for_testing_
= true;
540 void ProfileChooserView::ShowBubble(
541 profiles::BubbleViewMode view_mode
,
542 profiles::TutorialMode tutorial_mode
,
543 const signin::ManageAccountsParams
& manage_accounts_params
,
544 views::View
* anchor_view
,
545 views::BubbleBorder::Arrow arrow
,
546 views::BubbleBorder::BubbleAlignment border_alignment
,
548 // Don't start creating the view if it would be an empty fast user switcher.
549 // It has to happen here to prevent the view system from creating an empty
551 if (view_mode
== profiles::BUBBLE_VIEW_MODE_FAST_PROFILE_CHOOSER
&&
552 !profiles::HasProfileSwitchTargets(browser
->profile())) {
557 if (tutorial_mode
!= profiles::TUTORIAL_MODE_NONE
) {
558 profile_bubble_
->tutorial_mode_
= tutorial_mode
;
559 profile_bubble_
->ShowView(view_mode
, profile_bubble_
->avatar_menu_
.get());
564 profile_bubble_
= new ProfileChooserView(anchor_view
, arrow
, browser
,
565 view_mode
, tutorial_mode
, manage_accounts_params
.service_type
);
566 views::BubbleDelegateView::CreateBubble(profile_bubble_
);
567 profile_bubble_
->set_close_on_deactivate(close_on_deactivate_for_testing_
);
568 profile_bubble_
->SetAlignment(border_alignment
);
569 profile_bubble_
->GetWidget()->Show();
570 profile_bubble_
->SetArrowPaintType(views::BubbleBorder::PAINT_NONE
);
574 bool ProfileChooserView::IsShowing() {
575 return profile_bubble_
!= NULL
;
579 void ProfileChooserView::Hide() {
581 profile_bubble_
->GetWidget()->Close();
584 ProfileChooserView::ProfileChooserView(views::View
* anchor_view
,
585 views::BubbleBorder::Arrow arrow
,
587 profiles::BubbleViewMode view_mode
,
588 profiles::TutorialMode tutorial_mode
,
589 signin::GAIAServiceType service_type
)
590 : BubbleDelegateView(anchor_view
, arrow
),
592 view_mode_(view_mode
),
593 tutorial_mode_(tutorial_mode
),
594 gaia_service_type_(service_type
) {
595 // Reset the default margins inherited from the BubbleDelegateView.
596 // Add a small bottom inset so that the bubble's rounded corners show up.
597 set_margins(gfx::Insets(0, 0, 1, 0));
598 set_background(views::Background::CreateSolidBackground(
599 GetNativeTheme()->GetSystemColor(
600 ui::NativeTheme::kColorId_DialogBackground
)));
603 avatar_menu_
.reset(new AvatarMenu(
604 &g_browser_process
->profile_manager()->GetProfileInfoCache(),
607 avatar_menu_
->RebuildMenu();
609 ProfileOAuth2TokenService
* oauth2_token_service
=
610 ProfileOAuth2TokenServiceFactory::GetForProfile(browser_
->profile());
611 if (oauth2_token_service
)
612 oauth2_token_service
->AddObserver(this);
615 ProfileChooserView::~ProfileChooserView() {
616 ProfileOAuth2TokenService
* oauth2_token_service
=
617 ProfileOAuth2TokenServiceFactory::GetForProfile(browser_
->profile());
618 if (oauth2_token_service
)
619 oauth2_token_service
->RemoveObserver(this);
622 void ProfileChooserView::ResetView() {
623 open_other_profile_indexes_map_
.clear();
624 delete_account_button_map_
.clear();
625 reauth_account_button_map_
.clear();
626 manage_accounts_link_
= NULL
;
627 signin_current_profile_link_
= NULL
;
628 auth_error_email_button_
= NULL
;
629 current_profile_photo_
= NULL
;
630 current_profile_name_
= NULL
;
631 users_button_
= NULL
;
632 go_incognito_button_
= NULL
;
634 add_account_link_
= NULL
;
635 gaia_signin_cancel_button_
= NULL
;
636 remove_account_button_
= NULL
;
637 account_removal_cancel_button_
= NULL
;
638 add_person_button_
= NULL
;
639 disconnect_button_
= NULL
;
640 switch_user_cancel_button_
= NULL
;
641 tutorial_sync_settings_ok_button_
= NULL
;
642 tutorial_close_button_
= NULL
;
643 tutorial_sync_settings_link_
= NULL
;
644 tutorial_see_whats_new_button_
= NULL
;
645 tutorial_not_you_link_
= NULL
;
646 tutorial_learn_more_link_
= NULL
;
649 void ProfileChooserView::Init() {
650 // If view mode is PROFILE_CHOOSER but there is an auth error, force
651 // ACCOUNT_MANAGEMENT mode.
652 if (IsProfileChooser(view_mode_
) &&
653 HasAuthError(browser_
->profile()) &&
654 switches::IsEnableAccountConsistency() &&
655 avatar_menu_
->GetItemAt(avatar_menu_
->GetActiveProfileIndex()).
657 view_mode_
= profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT
;
660 // The arrow keys can be used to tab between items.
661 AddAccelerator(ui::Accelerator(ui::VKEY_DOWN
, ui::EF_NONE
));
662 AddAccelerator(ui::Accelerator(ui::VKEY_UP
, ui::EF_NONE
));
664 ShowView(view_mode_
, avatar_menu_
.get());
667 void ProfileChooserView::OnAvatarMenuChanged(
668 AvatarMenu
* avatar_menu
) {
669 if (IsProfileChooser(view_mode_
) ||
670 view_mode_
== profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT
) {
671 // Refresh the view with the new menu. We can't just update the local copy
672 // as this may have been triggered by a sign out action, in which case
673 // the view is being destroyed.
674 ShowView(view_mode_
, avatar_menu
);
678 void ProfileChooserView::OnRefreshTokenAvailable(
679 const std::string
& account_id
) {
680 if (view_mode_
== profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT
||
681 view_mode_
== profiles::BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT
||
682 view_mode_
== profiles::BUBBLE_VIEW_MODE_GAIA_REAUTH
) {
683 // The account management UI is only available through the
684 // --enable-account-consistency flag.
685 ShowView(switches::IsEnableAccountConsistency() ?
686 profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT
:
687 profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER
, avatar_menu_
.get());
691 void ProfileChooserView::OnRefreshTokenRevoked(const std::string
& account_id
) {
692 // Refresh the account management view when an account is removed from the
694 if (view_mode_
== profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT
)
695 ShowView(profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT
, avatar_menu_
.get());
698 void ProfileChooserView::ShowView(profiles::BubbleViewMode view_to_display
,
699 AvatarMenu
* avatar_menu
) {
700 // The account management view should only be displayed if the active profile
702 if (view_to_display
== profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT
) {
703 DCHECK(switches::IsEnableAccountConsistency());
704 const AvatarMenu::Item
& active_item
= avatar_menu
->GetItemAt(
705 avatar_menu
->GetActiveProfileIndex());
706 DCHECK(active_item
.signed_in
);
709 if (browser_
->profile()->IsSupervised() &&
710 (view_to_display
== profiles::BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT
||
711 view_to_display
== profiles::BUBBLE_VIEW_MODE_ACCOUNT_REMOVAL
)) {
712 LOG(WARNING
) << "Supervised user attempted to add/remove account";
717 RemoveAllChildViews(true);
718 view_mode_
= view_to_display
;
720 views::GridLayout
* layout
= nullptr;
721 views::View
* sub_view
= nullptr;
722 views::View
* view_to_focus
= nullptr;
723 switch (view_mode_
) {
724 case profiles::BUBBLE_VIEW_MODE_GAIA_SIGNIN
:
725 case profiles::BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT
:
726 case profiles::BUBBLE_VIEW_MODE_GAIA_REAUTH
:
727 layout
= CreateSingleColumnLayout(this, kFixedGaiaViewWidth
);
728 sub_view
= CreateGaiaSigninView(&view_to_focus
);
730 case profiles::BUBBLE_VIEW_MODE_ACCOUNT_REMOVAL
:
731 layout
= CreateSingleColumnLayout(this, kFixedAccountRemovalViewWidth
);
732 sub_view
= CreateAccountRemovalView();
734 case profiles::BUBBLE_VIEW_MODE_SWITCH_USER
:
735 layout
= CreateSingleColumnLayout(this, kFixedSwitchUserViewWidth
);
736 sub_view
= CreateSwitchUserView();
737 ProfileMetrics::LogProfileNewAvatarMenuNotYou(
738 ProfileMetrics::PROFILE_AVATAR_MENU_NOT_YOU_VIEW
);
740 case profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT
:
741 case profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER
:
742 case profiles::BUBBLE_VIEW_MODE_FAST_PROFILE_CHOOSER
:
743 layout
= CreateSingleColumnLayout(this, kFixedMenuWidth
);
744 sub_view
= CreateProfileChooserView(avatar_menu
);
747 // Clears tutorial mode for all non-profile-chooser views.
748 if (view_mode_
!= profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER
)
749 tutorial_mode_
= profiles::TUTORIAL_MODE_NONE
;
751 layout
->StartRow(1, 0);
752 layout
->AddView(sub_view
);
754 if (GetBubbleFrameView())
757 view_to_focus
->RequestFocus();
760 void ProfileChooserView::WindowClosing() {
761 DCHECK_EQ(profile_bubble_
, this);
762 profile_bubble_
= NULL
;
764 if (tutorial_mode_
== profiles::TUTORIAL_MODE_CONFIRM_SIGNIN
) {
765 LoginUIServiceFactory::GetForProfile(browser_
->profile())->
766 SyncConfirmationUIClosed(false /* configure_sync_first */);
770 bool ProfileChooserView::AcceleratorPressed(
771 const ui::Accelerator
& accelerator
) {
772 if (accelerator
.key_code() != ui::VKEY_DOWN
&&
773 accelerator
.key_code() != ui::VKEY_UP
)
774 return BubbleDelegateView::AcceleratorPressed(accelerator
);
775 // Move the focus up or down.
776 GetFocusManager()->AdvanceFocus(accelerator
.key_code() != ui::VKEY_DOWN
);
780 views::View
* ProfileChooserView::GetInitiallyFocusedView() {
781 return signin_current_profile_link_
;
784 bool ProfileChooserView::HandleContextMenu(
785 const content::ContextMenuParams
& params
) {
786 // Suppresses the context menu because some features, such as inspecting
787 // elements, are not appropriate in a bubble.
791 void ProfileChooserView::ButtonPressed(views::Button
* sender
,
792 const ui::Event
& event
) {
793 if (sender
== users_button_
) {
794 // If this is a guest session, close all the guest browser windows.
795 if (browser_
->profile()->IsGuestSession()) {
796 profiles::CloseGuestProfileWindows();
798 UserManager::Show(base::FilePath(),
799 profiles::USER_MANAGER_NO_TUTORIAL
,
800 profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION
);
802 PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_OPEN_USER_MANAGER
);
803 } else if (sender
== go_incognito_button_
) {
804 DCHECK(ShouldShowGoIncognito());
805 chrome::NewIncognitoWindow(browser_
);
806 PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_GO_INCOGNITO
);
807 } else if (sender
== lock_button_
) {
808 profiles::LockProfile(browser_
->profile());
809 PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_LOCK
);
810 } else if (sender
== auth_error_email_button_
) {
811 ShowView(profiles::BUBBLE_VIEW_MODE_GAIA_REAUTH
, avatar_menu_
.get());
812 } else if (sender
== tutorial_sync_settings_ok_button_
) {
813 LoginUIServiceFactory::GetForProfile(browser_
->profile())->
814 SyncConfirmationUIClosed(false /* configure_sync_first */);
816 ProfileMetrics::LogProfileNewAvatarMenuSignin(
817 ProfileMetrics::PROFILE_AVATAR_MENU_SIGNIN_OK
);
818 } else if (sender
== tutorial_close_button_
) {
819 DCHECK(tutorial_mode_
!= profiles::TUTORIAL_MODE_NONE
&&
820 tutorial_mode_
!= profiles::TUTORIAL_MODE_CONFIRM_SIGNIN
);
822 } else if (sender
== tutorial_see_whats_new_button_
) {
823 ProfileMetrics::LogProfileNewAvatarMenuUpgrade(
824 ProfileMetrics::PROFILE_AVATAR_MENU_UPGRADE_WHATS_NEW
);
825 UserManager::Show(base::FilePath(),
826 profiles::USER_MANAGER_TUTORIAL_OVERVIEW
,
827 profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION
);
828 } else if (sender
== remove_account_button_
) {
830 } else if (sender
== account_removal_cancel_button_
) {
831 account_id_to_remove_
.clear();
832 ShowView(profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT
, avatar_menu_
.get());
833 } else if (sender
== gaia_signin_cancel_button_
) {
834 // The account management view is only available with the
835 // --enable-account-consistency flag.
836 bool account_management_available
=
837 SigninManagerFactory::GetForProfile(browser_
->profile())->
839 switches::IsEnableAccountConsistency();
840 ShowView(account_management_available
?
841 profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT
:
842 profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER
, avatar_menu_
.get());
843 } else if (sender
== current_profile_photo_
) {
844 avatar_menu_
->EditProfile(avatar_menu_
->GetActiveProfileIndex());
845 PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_EDIT_IMAGE
);
846 } else if (sender
== signin_current_profile_link_
) {
847 ShowView(profiles::BUBBLE_VIEW_MODE_GAIA_SIGNIN
, avatar_menu_
.get());
848 } else if (sender
== add_person_button_
) {
849 ProfileMetrics::LogProfileNewAvatarMenuNotYou(
850 ProfileMetrics::PROFILE_AVATAR_MENU_NOT_YOU_ADD_PERSON
);
851 UserManager::Show(base::FilePath(),
852 profiles::USER_MANAGER_NO_TUTORIAL
,
853 profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION
);
854 } else if (sender
== disconnect_button_
) {
855 ProfileMetrics::LogProfileNewAvatarMenuNotYou(
856 ProfileMetrics::PROFILE_AVATAR_MENU_NOT_YOU_DISCONNECT
);
857 chrome::ShowSettings(browser_
);
858 } else if (sender
== switch_user_cancel_button_
) {
859 ShowView(profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER
, avatar_menu_
.get());
860 ProfileMetrics::LogProfileNewAvatarMenuNotYou(
861 ProfileMetrics::PROFILE_AVATAR_MENU_NOT_YOU_BACK
);
863 // Either one of the "other profiles", or one of the profile accounts
864 // buttons was pressed.
865 ButtonIndexes::const_iterator profile_match
=
866 open_other_profile_indexes_map_
.find(sender
);
867 if (profile_match
!= open_other_profile_indexes_map_
.end()) {
868 avatar_menu_
->SwitchToProfile(
869 profile_match
->second
,
870 ui::DispositionFromEventFlags(event
.flags()) == NEW_WINDOW
,
871 ProfileMetrics::SWITCH_PROFILE_ICON
);
873 // This was a profile accounts button.
874 AccountButtonIndexes::const_iterator account_match
=
875 delete_account_button_map_
.find(sender
);
876 if (account_match
!= delete_account_button_map_
.end()) {
877 account_id_to_remove_
= account_match
->second
;
878 ShowView(profiles::BUBBLE_VIEW_MODE_ACCOUNT_REMOVAL
,
881 account_match
= reauth_account_button_map_
.find(sender
);
882 DCHECK(account_match
!= reauth_account_button_map_
.end());
883 ShowView(profiles::BUBBLE_VIEW_MODE_GAIA_REAUTH
, avatar_menu_
.get());
889 void ProfileChooserView::RemoveAccount() {
890 DCHECK(!account_id_to_remove_
.empty());
891 ProfileOAuth2TokenService
* oauth2_token_service
=
892 ProfileOAuth2TokenServiceFactory::GetForProfile(browser_
->profile());
893 if (oauth2_token_service
) {
894 oauth2_token_service
->RevokeCredentials(account_id_to_remove_
);
895 PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_REMOVE_ACCT
);
897 account_id_to_remove_
.clear();
899 ShowView(profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT
, avatar_menu_
.get());
902 void ProfileChooserView::LinkClicked(views::Link
* sender
, int event_flags
) {
903 if (sender
== manage_accounts_link_
) {
904 // This link can either mean show/hide the account management view,
905 // depending on which view it is displayed. ShowView() will DCHECK if
906 // the account management view is displayed for non signed-in users.
908 view_mode_
== profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT
?
909 profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER
:
910 profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT
,
912 } else if (sender
== add_account_link_
) {
913 ShowView(profiles::BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT
, avatar_menu_
.get());
914 PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_ADD_ACCT
);
915 } else if (sender
== tutorial_sync_settings_link_
) {
916 LoginUIServiceFactory::GetForProfile(browser_
->profile())->
917 SyncConfirmationUIClosed(true /* configure_sync_first */);
918 tutorial_mode_
= profiles::TUTORIAL_MODE_NONE
;
919 ProfileMetrics::LogProfileNewAvatarMenuSignin(
920 ProfileMetrics::PROFILE_AVATAR_MENU_SIGNIN_SETTINGS
);
921 } else if (sender
== tutorial_not_you_link_
) {
922 ProfileMetrics::LogProfileNewAvatarMenuUpgrade(
923 ProfileMetrics::PROFILE_AVATAR_MENU_UPGRADE_NOT_YOU
);
924 ShowView(profiles::BUBBLE_VIEW_MODE_SWITCH_USER
, avatar_menu_
.get());
926 DCHECK(sender
== tutorial_learn_more_link_
);
927 signin_ui_util::ShowSigninErrorLearnMorePage(browser_
->profile());
931 void ProfileChooserView::StyledLabelLinkClicked(
932 const gfx::Range
& range
, int event_flags
) {
933 chrome::ShowSettings(browser_
);
936 bool ProfileChooserView::HandleKeyEvent(views::Textfield
* sender
,
937 const ui::KeyEvent
& key_event
) {
938 views::Textfield
* name_textfield
=
939 current_profile_name_
->profile_name_textfield();
940 DCHECK(sender
== name_textfield
);
942 if (key_event
.key_code() == ui::VKEY_RETURN
||
943 key_event
.key_code() == ui::VKEY_TAB
) {
944 // Pressing Tab/Enter commits the new profile name, unless it's empty.
945 base::string16 new_profile_name
= name_textfield
->text();
946 base::TrimWhitespace(new_profile_name
, base::TRIM_ALL
, &new_profile_name
);
947 if (new_profile_name
.empty())
950 const AvatarMenu::Item
& active_item
= avatar_menu_
->GetItemAt(
951 avatar_menu_
->GetActiveProfileIndex());
952 Profile
* profile
= g_browser_process
->profile_manager()->GetProfile(
953 active_item
.profile_path
);
956 if (profile
->IsLegacySupervised())
959 profiles::UpdateProfileName(profile
, new_profile_name
);
960 PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_EDIT_NAME
);
961 current_profile_name_
->ShowReadOnlyView();
967 void ProfileChooserView::PopulateCompleteProfileChooserView(
968 views::GridLayout
* layout
,
969 AvatarMenu
* avatar_menu
) {
970 // Separate items into active and alternatives.
971 Indexes other_profiles
;
972 views::View
* tutorial_view
= NULL
;
973 views::View
* current_profile_view
= NULL
;
974 views::View
* current_profile_accounts
= NULL
;
975 views::View
* option_buttons_view
= NULL
;
976 for (size_t i
= 0; i
< avatar_menu
->GetNumberOfItems(); ++i
) {
977 const AvatarMenu::Item
& item
= avatar_menu
->GetItemAt(i
);
979 option_buttons_view
= CreateOptionsView(
980 item
.signed_in
&& profiles::IsLockAvailable(browser_
->profile()));
981 current_profile_view
= CreateCurrentProfileView(item
, false);
982 if (IsProfileChooser(view_mode_
)) {
983 tutorial_view
= CreateTutorialViewIfNeeded(item
);
985 current_profile_accounts
= CreateCurrentProfileAccountsView(item
);
988 other_profiles
.push_back(i
);
993 // TODO(mlerman): update UMA stats for the new tutorial.
994 layout
->StartRow(1, 0);
995 layout
->AddView(tutorial_view
);
997 tutorial_mode_
= profiles::TUTORIAL_MODE_NONE
;
1000 if (!current_profile_view
) {
1001 // Guest windows don't have an active profile.
1002 current_profile_view
= CreateGuestProfileView();
1003 option_buttons_view
= CreateOptionsView(false);
1006 layout
->StartRow(1, 0);
1007 layout
->AddView(current_profile_view
);
1009 if (!IsProfileChooser(view_mode_
)) {
1010 DCHECK(current_profile_accounts
);
1011 layout
->StartRow(0, 0);
1012 layout
->AddView(new views::Separator(views::Separator::HORIZONTAL
));
1013 layout
->StartRow(1, 0);
1014 layout
->AddView(current_profile_accounts
);
1017 if (browser_
->profile()->IsSupervised()) {
1018 layout
->StartRow(0, 0);
1019 layout
->AddView(new views::Separator(views::Separator::HORIZONTAL
));
1020 layout
->StartRow(1, 0);
1021 layout
->AddView(CreateSupervisedUserDisclaimerView());
1024 layout
->StartRow(0, 0);
1025 layout
->AddView(new views::Separator(views::Separator::HORIZONTAL
));
1027 if (option_buttons_view
) {
1028 layout
->StartRow(0, 0);
1029 layout
->AddView(option_buttons_view
);
1033 void ProfileChooserView::PopulateMinimalProfileChooserView(
1034 views::GridLayout
* layout
,
1035 AvatarMenu
* avatar_menu
) {
1036 Indexes other_profiles
;
1037 for (size_t i
= 0; i
< avatar_menu
->GetNumberOfItems(); ++i
) {
1038 const AvatarMenu::Item
& item
= avatar_menu
->GetItemAt(i
);
1040 other_profiles
.push_back(i
);
1044 layout
->StartRow(1, 0);
1045 layout
->AddView(CreateOtherProfilesView(other_profiles
));
1048 views::View
* ProfileChooserView::CreateProfileChooserView(
1049 AvatarMenu
* avatar_menu
) {
1050 views::View
* view
= new views::View();
1051 views::GridLayout
* layout
= CreateSingleColumnLayout(view
, kFixedMenuWidth
);
1053 if (view_mode_
== profiles::BUBBLE_VIEW_MODE_FAST_PROFILE_CHOOSER
) {
1054 PopulateMinimalProfileChooserView(layout
, avatar_menu
);
1055 // The user is using right-click switching, no need to tell them about it.
1056 PrefService
* local_state
= g_browser_process
->local_state();
1057 local_state
->SetBoolean(
1058 prefs::kProfileAvatarRightClickTutorialDismissed
, true);
1060 PopulateCompleteProfileChooserView(layout
, avatar_menu
);
1066 void ProfileChooserView::DismissTutorial() {
1067 // Never shows the upgrade tutorial again if manually closed.
1068 if (tutorial_mode_
== profiles::TUTORIAL_MODE_WELCOME_UPGRADE
) {
1069 browser_
->profile()->GetPrefs()->SetInteger(
1070 prefs::kProfileAvatarTutorialShown
,
1071 signin_ui_util::kUpgradeWelcomeTutorialShowMax
+ 1);
1074 if (tutorial_mode_
== profiles::TUTORIAL_MODE_RIGHT_CLICK_SWITCHING
) {
1075 PrefService
* local_state
= g_browser_process
->local_state();
1076 local_state
->SetBoolean(
1077 prefs::kProfileAvatarRightClickTutorialDismissed
, true);
1080 tutorial_mode_
= profiles::TUTORIAL_MODE_NONE
;
1081 ShowView(profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER
, avatar_menu_
.get());
1084 views::View
* ProfileChooserView::CreateTutorialViewIfNeeded(
1085 const AvatarMenu::Item
& item
) {
1086 if (tutorial_mode_
== profiles::TUTORIAL_MODE_CONFIRM_SIGNIN
)
1087 return CreateSigninConfirmationView();
1089 if (tutorial_mode_
== profiles::TUTORIAL_MODE_SHOW_ERROR
)
1090 return CreateSigninErrorView();
1092 if (profiles::ShouldShowWelcomeUpgradeTutorial(
1093 browser_
->profile(), tutorial_mode_
)) {
1094 if (tutorial_mode_
!= profiles::TUTORIAL_MODE_WELCOME_UPGRADE
) {
1095 Profile
* profile
= browser_
->profile();
1096 const int show_count
= profile
->GetPrefs()->GetInteger(
1097 prefs::kProfileAvatarTutorialShown
);
1098 profile
->GetPrefs()->SetInteger(
1099 prefs::kProfileAvatarTutorialShown
, show_count
+ 1);
1102 return CreateWelcomeUpgradeTutorialView(item
);
1105 if (profiles::ShouldShowRightClickTutorial(browser_
->profile()))
1106 return CreateRightClickTutorialView();
1111 views::View
* ProfileChooserView::CreateTutorialView(
1112 profiles::TutorialMode tutorial_mode
,
1113 const base::string16
& title_text
,
1114 const base::string16
& content_text
,
1115 const base::string16
& link_text
,
1116 const base::string16
& button_text
,
1119 views::LabelButton
** button
,
1120 views::ImageButton
** close_button
) {
1121 tutorial_mode_
= tutorial_mode
;
1123 views::View
* view
= new views::View();
1124 view
->set_background(views::Background::CreateSolidBackground(
1125 profiles::kAvatarTutorialBackgroundColor
));
1126 views::GridLayout
* layout
= CreateSingleColumnLayout(view
,
1127 kFixedMenuWidth
- 2 * views::kButtonHEdgeMarginNew
);
1128 // Creates a second column set for buttons and links.
1129 views::ColumnSet
* button_columns
= layout
->AddColumnSet(1);
1130 button_columns
->AddColumn(views::GridLayout::LEADING
,
1131 views::GridLayout::CENTER
, 0, views::GridLayout::USE_PREF
, 0, 0);
1132 button_columns
->AddPaddingColumn(
1133 1, views::kUnrelatedControlHorizontalSpacing
);
1134 button_columns
->AddColumn(views::GridLayout::TRAILING
,
1135 views::GridLayout::CENTER
, 0, views::GridLayout::USE_PREF
, 0, 0);
1136 layout
->SetInsets(views::kButtonVEdgeMarginNew
,
1137 views::kButtonHEdgeMarginNew
,
1138 views::kButtonVEdgeMarginNew
,
1139 views::kButtonHEdgeMarginNew
);
1141 // Adds title and close button if needed.
1142 views::Label
* title_label
= new views::Label(title_text
);
1143 title_label
->SetMultiLine(true);
1144 title_label
->SetHorizontalAlignment(gfx::ALIGN_LEFT
);
1145 title_label
->SetAutoColorReadabilityEnabled(false);
1146 title_label
->SetEnabledColor(SK_ColorWHITE
);
1147 title_label
->SetFontList(ui::ResourceBundle::GetSharedInstance().GetFontList(
1148 ui::ResourceBundle::MediumFont
));
1151 layout
->StartRow(1, 1);
1152 layout
->AddView(title_label
);
1153 *close_button
= new views::ImageButton(this);
1154 (*close_button
)->SetImageAlignment(views::ImageButton::ALIGN_RIGHT
,
1155 views::ImageButton::ALIGN_MIDDLE
);
1156 ui::ResourceBundle
* rb
= &ui::ResourceBundle::GetSharedInstance();
1157 (*close_button
)->SetImage(views::ImageButton::STATE_NORMAL
,
1158 rb
->GetImageSkiaNamed(IDR_CLOSE_1
));
1159 (*close_button
)->SetImage(views::ImageButton::STATE_HOVERED
,
1160 rb
->GetImageSkiaNamed(IDR_CLOSE_1_H
));
1161 (*close_button
)->SetImage(views::ImageButton::STATE_PRESSED
,
1162 rb
->GetImageSkiaNamed(IDR_CLOSE_1_P
));
1163 layout
->AddView(*close_button
);
1165 layout
->StartRow(1, 0);
1166 layout
->AddView(title_label
);
1169 // Adds body content.
1170 views::Label
* content_label
= new views::Label(content_text
);
1171 content_label
->SetMultiLine(true);
1172 content_label
->SetHorizontalAlignment(gfx::ALIGN_LEFT
);
1173 content_label
->SetAutoColorReadabilityEnabled(false);
1174 content_label
->SetEnabledColor(profiles::kAvatarTutorialContentTextColor
);
1175 layout
->StartRowWithPadding(1, 0, 0, views::kRelatedControlVerticalSpacing
);
1176 layout
->AddView(content_label
);
1178 // Adds links and buttons.
1179 bool has_button
= !button_text
.empty();
1181 *button
= new views::LabelButton(this, button_text
);
1182 (*button
)->SetHorizontalAlignment(gfx::ALIGN_CENTER
);
1183 (*button
)->SetStyle(views::Button::STYLE_BUTTON
);
1186 bool has_link
= !link_text
.empty();
1188 *link
= CreateLink(link_text
, this);
1189 (*link
)->SetHorizontalAlignment(gfx::ALIGN_LEFT
);
1190 (*link
)->SetAutoColorReadabilityEnabled(false);
1191 (*link
)->SetEnabledColor(SK_ColorWHITE
);
1196 layout
->StartRowWithPadding(
1197 1, 0, 0, views::kUnrelatedControlVerticalSpacing
);
1198 layout
->AddView(*button
);
1200 layout
->StartRowWithPadding(
1201 1, 0, 0, views::kRelatedControlVerticalSpacing
);
1202 (*link
)->SetHorizontalAlignment(gfx::ALIGN_CENTER
);
1203 layout
->AddView(*link
);
1206 DCHECK(has_link
|| has_button
);
1207 layout
->StartRowWithPadding(
1208 1, 1, 0, views::kUnrelatedControlVerticalSpacing
);
1210 layout
->AddView(*link
);
1212 layout
->SkipColumns(1);
1214 layout
->AddView(*button
);
1216 layout
->SkipColumns(1);
1222 views::View
* ProfileChooserView::CreateCurrentProfileView(
1223 const AvatarMenu::Item
& avatar_item
,
1225 views::View
* view
= new views::View();
1226 int column_width
= kFixedMenuWidth
- 2 * views::kButtonHEdgeMarginNew
;
1227 views::GridLayout
* layout
= CreateSingleColumnLayout(view
, column_width
);
1228 layout
->SetInsets(views::kButtonVEdgeMarginNew
,
1229 views::kButtonHEdgeMarginNew
,
1230 views::kUnrelatedControlVerticalSpacing
,
1231 views::kButtonHEdgeMarginNew
);
1233 // Profile icon, centered.
1234 int x_offset
= (column_width
- kLargeImageSide
) / 2;
1235 current_profile_photo_
= new EditableProfilePhoto(
1236 this, avatar_item
.icon
, !is_guest
,
1237 gfx::Rect(x_offset
, 0, kLargeImageSide
, kLargeImageSide
));
1238 SizedContainer
* profile_icon_container
=
1239 new SizedContainer(gfx::Size(column_width
, kLargeImageSide
));
1240 profile_icon_container
->AddChildView(current_profile_photo_
);
1242 if (browser_
->profile()->IsSupervised()) {
1243 views::ImageView
* supervised_icon
= new views::ImageView();
1244 supervised_icon
->SetImage(CreateBadgeForProfile(browser_
->profile()));
1245 gfx::Size preferred_size
= supervised_icon
->GetPreferredSize();
1246 gfx::Rect parent_bounds
= current_profile_photo_
->bounds();
1247 supervised_icon
->SetBounds(
1248 parent_bounds
.right() - preferred_size
.width(),
1249 parent_bounds
.bottom() - preferred_size
.height(),
1250 preferred_size
.width(),
1251 preferred_size
.height());
1252 profile_icon_container
->AddChildView(supervised_icon
);
1255 layout
->StartRow(1, 0);
1256 layout
->AddView(profile_icon_container
);
1258 // Profile name, centered.
1259 bool editing_allowed
= !is_guest
&&
1260 !browser_
->profile()->IsLegacySupervised();
1261 current_profile_name_
= new EditableProfileName(
1263 profiles::GetAvatarNameForProfile(browser_
->profile()->GetPath()),
1265 layout
->StartRowWithPadding(1, 0, 0,
1266 views::kRelatedControlSmallVerticalSpacing
);
1267 layout
->StartRow(1, 0);
1268 layout
->AddView(current_profile_name_
);
1273 // The available links depend on the type of profile that is active.
1274 if (avatar_item
.signed_in
) {
1275 layout
->StartRow(1, 0);
1276 if (switches::IsEnableAccountConsistency()) {
1277 base::string16 link_title
= l10n_util::GetStringUTF16(
1278 IsProfileChooser(view_mode_
) ?
1279 IDS_PROFILES_PROFILE_MANAGE_ACCOUNTS_BUTTON
:
1280 IDS_PROFILES_PROFILE_HIDE_MANAGE_ACCOUNTS_BUTTON
);
1281 manage_accounts_link_
= CreateLink(link_title
, this);
1282 manage_accounts_link_
->SetHorizontalAlignment(gfx::ALIGN_CENTER
);
1283 layout
->AddView(manage_accounts_link_
);
1285 // Badge the email address if there's an authentication error.
1286 if (HasAuthError(browser_
->profile())) {
1287 auth_error_email_button_
=
1288 new RightAlignedIconLabelButton(this, avatar_item
.username
);
1289 auth_error_email_button_
->SetElideBehavior(gfx::ELIDE_EMAIL
);
1291 ui::CommonThemeGetSystemColor(ui::NativeTheme::kColorId_ChromeIconGrey
,
1293 auth_error_email_button_
->SetImage(
1294 views::LabelButton::STATE_NORMAL
,
1295 gfx::CreateVectorIcon(gfx::VectorIconId::WARNING
, 18, icon_color
));
1297 auth_error_email_button_
->SetTextColor(
1298 views::LabelButton::STATE_NORMAL
,
1299 ui::NativeTheme::instance()->GetSystemColor(
1300 ui::NativeTheme::kColorId_LinkEnabled
));
1301 auth_error_email_button_
->SetFocusable(true);
1302 gfx::Insets insets
=
1303 views::LabelButtonAssetBorder::GetDefaultInsetsForStyle(
1304 views::Button::STYLE_TEXTBUTTON
);
1305 auth_error_email_button_
->SetBorder(views::Border::CreateEmptyBorder(
1306 insets
.top(), insets
.left(), insets
.bottom(), insets
.right()));
1307 layout
->AddView(auth_error_email_button_
);
1309 // Add a small padding between the email button and the profile name.
1310 layout
->StartRowWithPadding(1, 0, 0, 2);
1311 views::Label
* email_label
= new views::Label(avatar_item
.username
);
1312 email_label
->SetElideBehavior(gfx::ELIDE_EMAIL
);
1313 email_label
->SetEnabled(false);
1314 layout
->AddView(email_label
);
1318 SigninManagerBase
* signin_manager
= SigninManagerFactory::GetForProfile(
1319 browser_
->profile()->GetOriginalProfile());
1320 if (signin_manager
->IsSigninAllowed()) {
1321 views::Label
* promo
= new views::Label(
1322 l10n_util::GetStringUTF16(IDS_PROFILES_SIGNIN_PROMO
));
1323 promo
->SetMultiLine(true);
1324 promo
->SetHorizontalAlignment(gfx::ALIGN_LEFT
);
1325 layout
->StartRowWithPadding(1, 0, 0,
1326 views::kRelatedControlSmallVerticalSpacing
);
1327 layout
->StartRow(1, 0);
1328 layout
->AddView(promo
);
1330 signin_current_profile_link_
= new views::BlueButton(
1331 this, l10n_util::GetStringFUTF16(IDS_SYNC_START_SYNC_BUTTON_LABEL
,
1332 l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME
)));
1333 layout
->StartRowWithPadding(1, 0, 0,
1334 views::kRelatedControlVerticalSpacing
);
1335 layout
->StartRow(1, 0);
1336 layout
->AddView(signin_current_profile_link_
);
1343 views::View
* ProfileChooserView::CreateGuestProfileView() {
1344 gfx::Image guest_icon
=
1345 ui::ResourceBundle::GetSharedInstance().GetImageNamed(
1346 profiles::GetPlaceholderAvatarIconResourceID());
1347 AvatarMenu::Item
guest_avatar_item(0, 0, guest_icon
);
1348 guest_avatar_item
.active
= true;
1349 guest_avatar_item
.name
= l10n_util::GetStringUTF16(
1350 IDS_PROFILES_GUEST_PROFILE_NAME
);
1351 guest_avatar_item
.signed_in
= false;
1353 return CreateCurrentProfileView(guest_avatar_item
, true);
1356 views::View
* ProfileChooserView::CreateOtherProfilesView(
1357 const Indexes
& avatars_to_show
) {
1358 views::View
* view
= new views::View();
1359 views::GridLayout
* layout
= CreateSingleColumnLayout(view
, kFixedMenuWidth
);
1361 for (size_t index
: avatars_to_show
) {
1362 const AvatarMenu::Item
& item
= avatar_menu_
->GetItemAt(index
);
1363 const int kSmallImageSide
= 32;
1365 // Use the low-res, small default avatars in the fast user switcher, like
1366 // we do in the menu bar.
1367 gfx::Image item_icon
;
1369 AvatarMenu::GetImageForMenuButton(
1370 item
.profile_path
, &item_icon
, &is_rectangle
);
1372 gfx::Image image
= profiles::GetSizedAvatarIcon(
1373 item_icon
, true, kSmallImageSide
, kSmallImageSide
);
1375 views::LabelButton
* button
= new BackgroundColorHoverButton(
1377 profiles::GetProfileSwitcherTextForItem(item
),
1378 *image
.ToImageSkia());
1379 open_other_profile_indexes_map_
[button
] = index
;
1381 layout
->StartRow(1, 0);
1382 layout
->AddView(new views::Separator(views::Separator::HORIZONTAL
));
1383 layout
->StartRow(1, 0);
1384 layout
->AddView(button
);
1390 views::View
* ProfileChooserView::CreateOptionsView(bool display_lock
) {
1391 views::View
* view
= new views::View();
1392 views::GridLayout
* layout
= CreateSingleColumnLayout(view
, kFixedMenuWidth
);
1394 base::string16 text
= browser_
->profile()->IsGuestSession() ?
1395 l10n_util::GetStringUTF16(IDS_PROFILES_EXIT_GUEST
) :
1396 l10n_util::GetStringUTF16(IDS_PROFILES_SWITCH_USERS_BUTTON
);
1398 ui::CommonThemeGetSystemColor(ui::NativeTheme::kColorId_ChromeIconGrey
,
1400 const int kIconSize
= 16;
1401 users_button_
= new BackgroundColorHoverButton(
1402 this, text
, gfx::CreateVectorIcon(gfx::VectorIconId::ACCOUNT_BOX
,
1403 kIconSize
, icon_color
));
1404 layout
->StartRow(1, 0);
1405 layout
->AddView(users_button_
);
1407 if (ShouldShowGoIncognito()) {
1408 layout
->StartRow(1, 0);
1409 layout
->AddView(new views::Separator(views::Separator::HORIZONTAL
));
1411 ui::ResourceBundle
* rb
= &ui::ResourceBundle::GetSharedInstance();
1412 go_incognito_button_
= new BackgroundColorHoverButton(
1414 l10n_util::GetStringUTF16(IDS_PROFILES_GO_INCOGNITO_BUTTON
),
1415 *rb
->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_INCOGNITO
));
1416 layout
->StartRow(1, 0);
1417 layout
->AddView(go_incognito_button_
);
1421 layout
->StartRow(1, 0);
1422 layout
->AddView(new views::Separator(views::Separator::HORIZONTAL
));
1424 lock_button_
= new BackgroundColorHoverButton(
1425 this, l10n_util::GetStringUTF16(IDS_PROFILES_PROFILE_SIGNOUT_BUTTON
),
1426 gfx::CreateVectorIcon(gfx::VectorIconId::LOCK
, kIconSize
, icon_color
));
1427 layout
->StartRow(1, 0);
1428 layout
->AddView(lock_button_
);
1433 views::View
* ProfileChooserView::CreateSupervisedUserDisclaimerView() {
1434 views::View
* view
= new views::View();
1435 views::GridLayout
* layout
= CreateSingleColumnLayout(
1436 view
, kFixedMenuWidth
- 2 * views::kButtonHEdgeMarginNew
);
1437 layout
->SetInsets(views::kRelatedControlVerticalSpacing
,
1438 views::kButtonHEdgeMarginNew
,
1439 views::kRelatedControlVerticalSpacing
,
1440 views::kButtonHEdgeMarginNew
);
1441 views::Label
* disclaimer
= new views::Label(
1442 avatar_menu_
->GetSupervisedUserInformation());
1443 disclaimer
->SetMultiLine(true);
1444 disclaimer
->SetAllowCharacterBreak(true);
1445 disclaimer
->SetHorizontalAlignment(gfx::ALIGN_LEFT
);
1446 ui::ResourceBundle
* rb
= &ui::ResourceBundle::GetSharedInstance();
1447 disclaimer
->SetFontList(rb
->GetFontList(ui::ResourceBundle::SmallFont
));
1448 layout
->StartRow(1, 0);
1449 layout
->AddView(disclaimer
);
1454 views::View
* ProfileChooserView::CreateCurrentProfileAccountsView(
1455 const AvatarMenu::Item
& avatar_item
) {
1456 DCHECK(avatar_item
.signed_in
);
1457 views::View
* view
= new views::View();
1458 view
->set_background(views::Background::CreateSolidBackground(
1459 profiles::kAvatarBubbleAccountsBackgroundColor
));
1460 views::GridLayout
* layout
= CreateSingleColumnLayout(view
, kFixedMenuWidth
);
1462 Profile
* profile
= browser_
->profile();
1463 std::string primary_account
=
1464 SigninManagerFactory::GetForProfile(profile
)->GetAuthenticatedAccountId();
1465 DCHECK(!primary_account
.empty());
1466 std::vector
<std::string
>accounts
=
1467 profiles::GetSecondaryAccountsForProfile(profile
, primary_account
);
1469 // Get state of authentication error, if any.
1470 std::string error_account_id
= GetAuthErrorAccountId(profile
);
1472 // The primary account should always be listed first.
1473 // TODO(rogerta): we still need to further differentiate the primary account
1474 // from the others in the UI, so more work is likely required here:
1475 // crbug.com/311124.
1476 CreateAccountButton(layout
, primary_account
, true,
1477 error_account_id
== primary_account
, kFixedMenuWidth
);
1478 for (size_t i
= 0; i
< accounts
.size(); ++i
)
1479 CreateAccountButton(layout
, accounts
[i
], false,
1480 error_account_id
== accounts
[i
], kFixedMenuWidth
);
1482 if (!profile
->IsSupervised()) {
1483 layout
->AddPaddingRow(0, views::kRelatedControlVerticalSpacing
);
1485 add_account_link_
= CreateLink(l10n_util::GetStringFUTF16(
1486 IDS_PROFILES_PROFILE_ADD_ACCOUNT_BUTTON
, avatar_item
.name
), this);
1487 add_account_link_
->SetBorder(views::Border::CreateEmptyBorder(
1488 0, views::kButtonVEdgeMarginNew
,
1489 views::kRelatedControlVerticalSpacing
, 0));
1490 layout
->StartRow(1, 0);
1491 layout
->AddView(add_account_link_
);
1497 void ProfileChooserView::CreateAccountButton(views::GridLayout
* layout
,
1498 const std::string
& account_id
,
1499 bool is_primary_account
,
1500 bool reauth_required
,
1502 std::string email
= signin_ui_util::GetDisplayEmail(browser_
->profile(),
1504 ui::ResourceBundle
* rb
= &ui::ResourceBundle::GetSharedInstance();
1505 const gfx::ImageSkia
* delete_default_image
=
1506 rb
->GetImageNamed(IDR_CLOSE_1
).ToImageSkia();
1507 const int kDeleteButtonWidth
= delete_default_image
->width();
1508 gfx::ImageSkia warning_default_image
;
1509 int warning_button_width
= 0;
1510 if (reauth_required
) {
1512 ui::CommonThemeGetSystemColor(ui::NativeTheme::kColorId_ChromeIconGrey
,
1514 const int kIconSize
= 18;
1515 warning_default_image
= gfx::CreateVectorIcon(gfx::VectorIconId::WARNING
,
1516 kIconSize
, icon_color
);
1517 warning_button_width
= kIconSize
+ views::kRelatedButtonHSpacing
;
1519 int available_width
= width
- 2 * views::kButtonHEdgeMarginNew
-
1520 kDeleteButtonWidth
- warning_button_width
;
1521 views::LabelButton
* email_button
= new BackgroundColorHoverButton(
1522 reauth_required
? this : NULL
,
1523 base::UTF8ToUTF16(email
),
1524 warning_default_image
);
1525 email_button
->SetElideBehavior(gfx::ELIDE_EMAIL
);
1526 email_button
->SetMinSize(gfx::Size(0, kButtonHeight
));
1527 email_button
->SetMaxSize(gfx::Size(available_width
, kButtonHeight
));
1528 layout
->StartRow(1, 0);
1529 layout
->AddView(email_button
);
1531 if (reauth_required
)
1532 reauth_account_button_map_
[email_button
] = account_id
;
1535 if (!browser_
->profile()->IsSupervised()) {
1536 views::ImageButton
* delete_button
= new views::ImageButton(this);
1537 delete_button
->SetImageAlignment(views::ImageButton::ALIGN_RIGHT
,
1538 views::ImageButton::ALIGN_MIDDLE
);
1539 delete_button
->SetImage(views::ImageButton::STATE_NORMAL
,
1540 delete_default_image
);
1541 delete_button
->SetImage(views::ImageButton::STATE_HOVERED
,
1542 rb
->GetImageSkiaNamed(IDR_CLOSE_1_H
));
1543 delete_button
->SetImage(views::ImageButton::STATE_PRESSED
,
1544 rb
->GetImageSkiaNamed(IDR_CLOSE_1_P
));
1545 delete_button
->SetBounds(
1546 width
- views::kButtonHEdgeMarginNew
- kDeleteButtonWidth
,
1547 0, kDeleteButtonWidth
, kButtonHeight
);
1549 email_button
->set_notify_enter_exit_on_child(true);
1550 email_button
->AddChildView(delete_button
);
1552 // Save the original email address, as the button text could be elided.
1553 delete_account_button_map_
[delete_button
] = account_id
;
1557 views::View
* ProfileChooserView::CreateGaiaSigninView(
1558 views::View
** signin_content_view
) {
1562 switch (view_mode_
) {
1563 case profiles::BUBBLE_VIEW_MODE_GAIA_SIGNIN
:
1564 url
= signin::GetPromoURL(signin_metrics::SOURCE_AVATAR_BUBBLE_SIGN_IN
,
1565 false /* auto_close */,
1566 true /* is_constrained */);
1567 message_id
= IDS_PROFILES_GAIA_SIGNIN_TITLE
;
1569 case profiles::BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT
:
1570 url
= signin::GetPromoURL(
1571 signin_metrics::SOURCE_AVATAR_BUBBLE_ADD_ACCOUNT
,
1572 false /* auto_close */,
1573 true /* is_constrained */);
1574 message_id
= IDS_PROFILES_GAIA_ADD_ACCOUNT_TITLE
;
1576 case profiles::BUBBLE_VIEW_MODE_GAIA_REAUTH
: {
1577 DCHECK(HasAuthError(browser_
->profile()));
1578 url
= signin::GetReauthURL(browser_
->profile(),
1579 GetAuthErrorAccountId(browser_
->profile()));
1580 message_id
= IDS_PROFILES_GAIA_REAUTH_TITLE
;
1584 NOTREACHED() << "Called with invalid mode=" << view_mode_
;
1588 // Adds Gaia signin webview
1589 Profile
* profile
= browser_
->profile();
1590 views::WebView
* web_view
= new views::WebView(profile
);
1591 web_view
->LoadInitialURL(url
);
1592 web_view
->GetWebContents()->SetDelegate(this);
1593 web_view
->SetPreferredSize(
1594 gfx::Size(kFixedGaiaViewWidth
, kFixedGaiaViewHeight
));
1595 content::RenderWidgetHostView
* rwhv
=
1596 web_view
->GetWebContents()->GetRenderWidgetHostView();
1598 rwhv
->SetBackgroundColor(profiles::kAvatarBubbleGaiaBackgroundColor
);
1599 TitleCard
* title_card
= new TitleCard(l10n_util::GetStringUTF16(message_id
),
1601 &gaia_signin_cancel_button_
);
1602 if (signin_content_view
)
1603 *signin_content_view
= web_view
;
1604 return TitleCard::AddPaddedTitleCard(
1605 web_view
, title_card
, kFixedGaiaViewWidth
);
1608 views::View
* ProfileChooserView::CreateAccountRemovalView() {
1609 views::View
* view
= new views::View();
1610 views::GridLayout
* layout
= CreateSingleColumnLayout(
1611 view
, kFixedAccountRemovalViewWidth
- 2 * views::kButtonHEdgeMarginNew
);
1612 layout
->SetInsets(0,
1613 views::kButtonHEdgeMarginNew
,
1614 views::kButtonVEdgeMarginNew
,
1615 views::kButtonHEdgeMarginNew
);
1617 const std::string
& primary_account
= SigninManagerFactory::GetForProfile(
1618 browser_
->profile())->GetAuthenticatedAccountId();
1619 bool is_primary_account
= primary_account
== account_id_to_remove_
;
1622 layout
->StartRowWithPadding(1, 0, 0, views::kUnrelatedControlVerticalSpacing
);
1623 ui::ResourceBundle
* rb
= &ui::ResourceBundle::GetSharedInstance();
1624 const gfx::FontList
& small_font_list
=
1625 rb
->GetFontList(ui::ResourceBundle::SmallFont
);
1627 if (is_primary_account
) {
1628 std::string email
= signin_ui_util::GetDisplayEmail(browser_
->profile(),
1629 account_id_to_remove_
);
1630 std::vector
<size_t> offsets
;
1631 const base::string16 settings_text
=
1632 l10n_util::GetStringUTF16(IDS_PROFILES_SETTINGS_LINK
);
1633 const base::string16 primary_account_removal_text
=
1634 l10n_util::GetStringFUTF16(IDS_PROFILES_PRIMARY_ACCOUNT_REMOVAL_TEXT
,
1635 base::UTF8ToUTF16(email
), settings_text
, &offsets
);
1636 views::StyledLabel
* primary_account_removal_label
=
1637 new views::StyledLabel(primary_account_removal_text
, this);
1638 primary_account_removal_label
->AddStyleRange(
1639 gfx::Range(offsets
[1], offsets
[1] + settings_text
.size()),
1640 views::StyledLabel::RangeStyleInfo::CreateForLink());
1641 primary_account_removal_label
->SetBaseFontList(small_font_list
);
1642 layout
->AddView(primary_account_removal_label
);
1644 views::Label
* content_label
= new views::Label(
1645 l10n_util::GetStringUTF16(IDS_PROFILES_ACCOUNT_REMOVAL_TEXT
));
1646 content_label
->SetMultiLine(true);
1647 content_label
->SetHorizontalAlignment(gfx::ALIGN_LEFT
);
1648 content_label
->SetFontList(small_font_list
);
1649 layout
->AddView(content_label
);
1653 if (!is_primary_account
) {
1654 remove_account_button_
= new views::BlueButton(
1655 this, l10n_util::GetStringUTF16(IDS_PROFILES_ACCOUNT_REMOVAL_BUTTON
));
1656 remove_account_button_
->SetHorizontalAlignment(
1658 layout
->StartRowWithPadding(
1659 1, 0, 0, views::kUnrelatedControlVerticalSpacing
);
1660 layout
->AddView(remove_account_button_
);
1662 layout
->AddPaddingRow(0, views::kUnrelatedControlVerticalSpacing
);
1665 TitleCard
* title_card
= new TitleCard(
1666 l10n_util::GetStringUTF16(IDS_PROFILES_ACCOUNT_REMOVAL_TITLE
),
1667 this, &account_removal_cancel_button_
);
1668 return TitleCard::AddPaddedTitleCard(view
, title_card
,
1669 kFixedAccountRemovalViewWidth
);
1672 views::View
* ProfileChooserView::CreateWelcomeUpgradeTutorialView(
1673 const AvatarMenu::Item
& avatar_item
) {
1674 ProfileMetrics::LogProfileNewAvatarMenuUpgrade(
1675 ProfileMetrics::PROFILE_AVATAR_MENU_UPGRADE_VIEW
);
1677 // For local profiles, the "Not you" link doesn't make sense.
1678 base::string16 link_message
= avatar_item
.signed_in
?
1679 l10n_util::GetStringFUTF16(IDS_PROFILES_NOT_YOU
, avatar_item
.name
) :
1682 return CreateTutorialView(
1683 profiles::TUTORIAL_MODE_WELCOME_UPGRADE
,
1684 l10n_util::GetStringUTF16(
1685 IDS_PROFILES_WELCOME_UPGRADE_TUTORIAL_TITLE
),
1686 l10n_util::GetStringUTF16(
1687 IDS_PROFILES_WELCOME_UPGRADE_TUTORIAL_CONTENT_TEXT
),
1689 l10n_util::GetStringUTF16(IDS_PROFILES_TUTORIAL_WHATS_NEW_BUTTON
),
1690 true /* stack_button */,
1691 &tutorial_not_you_link_
,
1692 &tutorial_see_whats_new_button_
,
1693 &tutorial_close_button_
);
1696 views::View
* ProfileChooserView::CreateSigninConfirmationView() {
1697 ProfileMetrics::LogProfileNewAvatarMenuSignin(
1698 ProfileMetrics::PROFILE_AVATAR_MENU_SIGNIN_VIEW
);
1700 return CreateTutorialView(
1701 profiles::TUTORIAL_MODE_CONFIRM_SIGNIN
,
1702 l10n_util::GetStringUTF16(IDS_PROFILES_CONFIRM_SIGNIN_TUTORIAL_TITLE
),
1703 l10n_util::GetStringUTF16(
1704 IDS_PROFILES_CONFIRM_SIGNIN_TUTORIAL_CONTENT_TEXT
),
1705 l10n_util::GetStringUTF16(IDS_PROFILES_SYNC_SETTINGS_LINK
),
1706 l10n_util::GetStringUTF16(IDS_PROFILES_TUTORIAL_OK_BUTTON
),
1707 false /* stack_button */,
1708 &tutorial_sync_settings_link_
,
1709 &tutorial_sync_settings_ok_button_
,
1710 NULL
/* close_button*/);
1713 views::View
* ProfileChooserView::CreateSigninErrorView() {
1714 LoginUIService
* login_ui_service
=
1715 LoginUIServiceFactory::GetForProfile(browser_
->profile());
1716 base::string16
last_login_result(login_ui_service
->GetLastLoginResult());
1717 return CreateTutorialView(
1718 profiles::TUTORIAL_MODE_SHOW_ERROR
,
1719 l10n_util::GetStringUTF16(IDS_PROFILES_ERROR_TUTORIAL_TITLE
),
1721 l10n_util::GetStringUTF16(IDS_PROFILES_PROFILE_TUTORIAL_LEARN_MORE
),
1723 false /* stack_button */,
1724 &tutorial_learn_more_link_
,
1726 &tutorial_close_button_
);
1729 views::View
* ProfileChooserView::CreateRightClickTutorialView() {
1730 return CreateTutorialView(
1731 profiles::TUTORIAL_MODE_RIGHT_CLICK_SWITCHING
,
1732 l10n_util::GetStringUTF16(IDS_PROFILES_RIGHT_CLICK_TUTORIAL_TITLE
),
1733 l10n_util::GetStringUTF16(IDS_PROFILES_RIGHT_CLICK_TUTORIAL_CONTENT_TEXT
),
1735 l10n_util::GetStringUTF16(IDS_PROFILES_TUTORIAL_OK_BUTTON
),
1738 &tutorial_sync_settings_ok_button_
,
1742 views::View
* ProfileChooserView::CreateSwitchUserView() {
1743 views::View
* view
= new views::View();
1744 views::GridLayout
* layout
= CreateSingleColumnLayout(
1745 view
, kFixedSwitchUserViewWidth
);
1746 views::ColumnSet
* columns
= layout
->AddColumnSet(1);
1747 columns
->AddPaddingColumn(0, views::kButtonHEdgeMarginNew
);
1749 kFixedSwitchUserViewWidth
- 2 * views::kButtonHEdgeMarginNew
;
1750 columns
->AddColumn(views::GridLayout::FILL
, views::GridLayout::FILL
, 0,
1751 views::GridLayout::FIXED
, label_width
, label_width
);
1752 columns
->AddPaddingColumn(0, views::kButtonHEdgeMarginNew
);
1755 layout
->StartRowWithPadding(1, 1, 0, views::kUnrelatedControlVerticalSpacing
);
1756 ui::ResourceBundle
* rb
= &ui::ResourceBundle::GetSharedInstance();
1757 const gfx::FontList
& small_font_list
=
1758 rb
->GetFontList(ui::ResourceBundle::SmallFont
);
1759 const AvatarMenu::Item
& avatar_item
=
1760 avatar_menu_
->GetItemAt(avatar_menu_
->GetActiveProfileIndex());
1761 views::Label
* content_label
= new views::Label(
1762 l10n_util::GetStringFUTF16(
1763 IDS_PROFILES_NOT_YOU_CONTENT_TEXT
, avatar_item
.name
));
1764 content_label
->SetMultiLine(true);
1765 content_label
->SetHorizontalAlignment(gfx::ALIGN_LEFT
);
1766 content_label
->SetFontList(small_font_list
);
1767 layout
->AddView(content_label
);
1769 // Adds "Add person" button.
1770 layout
->StartRowWithPadding(1, 0, 0, views::kUnrelatedControlVerticalSpacing
);
1771 layout
->AddView(new views::Separator(views::Separator::HORIZONTAL
));
1773 const int kIconSize
= 24;
1775 ui::CommonThemeGetSystemColor(ui::NativeTheme::kColorId_ChromeIconGrey
,
1777 add_person_button_
= new BackgroundColorHoverButton(
1778 this, l10n_util::GetStringUTF16(IDS_PROFILES_ADD_PERSON_BUTTON
),
1779 gfx::CreateVectorIcon(gfx::VectorIconId::ACCOUNT_BOX
, kIconSize
,
1781 layout
->StartRow(1, 0);
1782 layout
->AddView(add_person_button_
);
1784 // Adds "Disconnect your Google Account" button.
1785 layout
->StartRow(1, 0);
1786 layout
->AddView(new views::Separator(views::Separator::HORIZONTAL
));
1788 disconnect_button_
= new BackgroundColorHoverButton(
1789 this, l10n_util::GetStringUTF16(IDS_PROFILES_DISCONNECT_BUTTON
),
1790 gfx::CreateVectorIcon(gfx::VectorIconId::REMOVE_BOX
, kIconSize
,
1792 layout
->StartRow(1, 0);
1793 layout
->AddView(disconnect_button_
);
1795 TitleCard
* title_card
= new TitleCard(
1796 l10n_util::GetStringFUTF16(IDS_PROFILES_NOT_YOU
, avatar_item
.name
),
1797 this, &switch_user_cancel_button_
);
1798 return TitleCard::AddPaddedTitleCard(view
, title_card
,
1799 kFixedSwitchUserViewWidth
);
1802 bool ProfileChooserView::ShouldShowGoIncognito() const {
1803 bool incognito_available
=
1804 IncognitoModePrefs::GetAvailability(browser_
->profile()->GetPrefs()) !=
1805 IncognitoModePrefs::DISABLED
;
1806 return incognito_available
&& !browser_
->profile()->IsGuestSession();
1809 void ProfileChooserView::PostActionPerformed(
1810 ProfileMetrics::ProfileDesktopMenu action_performed
) {
1811 ProfileMetrics::LogProfileDesktopMenu(action_performed
, gaia_service_type_
);
1812 gaia_service_type_
= signin::GAIA_SERVICE_TYPE_NONE
;