Don't show supervised user as "already on this device" while they're being imported.
[chromium-blink-merge.git] / chrome / browser / ui / views / profiles / profile_chooser_view.cc
blob14c9241c639c3b66443a939aaa47ce828104631b
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/ui/views/profiles/profile_chooser_view.h"
7 #include "base/prefs/pref_service.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "chrome/browser/browser_process.h"
10 #include "chrome/browser/lifetime/application_lifetime.h"
11 #include "chrome/browser/prefs/incognito_mode_prefs.h"
12 #include "chrome/browser/profiles/profile_avatar_icon_util.h"
13 #include "chrome/browser/profiles/profile_info_cache.h"
14 #include "chrome/browser/profiles/profile_manager.h"
15 #include "chrome/browser/profiles/profile_metrics.h"
16 #include "chrome/browser/profiles/profile_window.h"
17 #include "chrome/browser/profiles/profiles_state.h"
18 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
19 #include "chrome/browser/signin/signin_error_controller_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/compositor/clip_transform_recorder.h"
48 #include "ui/gfx/canvas.h"
49 #include "ui/gfx/image/image.h"
50 #include "ui/gfx/image/image_skia.h"
51 #include "ui/gfx/path.h"
52 #include "ui/gfx/skia_util.h"
53 #include "ui/gfx/text_elider.h"
54 #include "ui/native_theme/native_theme.h"
55 #include "ui/views/controls/button/blue_button.h"
56 #include "ui/views/controls/button/image_button.h"
57 #include "ui/views/controls/button/label_button.h"
58 #include "ui/views/controls/button/label_button_border.h"
59 #include "ui/views/controls/button/menu_button.h"
60 #include "ui/views/controls/label.h"
61 #include "ui/views/controls/link.h"
62 #include "ui/views/controls/separator.h"
63 #include "ui/views/controls/styled_label.h"
64 #include "ui/views/controls/textfield/textfield.h"
65 #include "ui/views/controls/webview/webview.h"
66 #include "ui/views/layout/grid_layout.h"
67 #include "ui/views/layout/layout_constants.h"
68 #include "ui/views/widget/widget.h"
70 namespace {
72 // Helpers --------------------------------------------------------------------
74 const int kFixedMenuWidth = 250;
75 const int kButtonHeight = 32;
76 const int kFixedGaiaViewHeight = 440;
77 const int kFixedGaiaViewWidth = 360;
78 const int kFixedAccountRemovalViewWidth = 280;
79 const int kFixedSwitchUserViewWidth = 320;
80 const int kLargeImageSide = 88;
82 const int kVerticalSpacing = 16;
84 bool IsProfileChooser(profiles::BubbleViewMode mode) {
85 return mode == profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER ||
86 mode == profiles::BUBBLE_VIEW_MODE_FAST_PROFILE_CHOOSER;
89 // Creates a GridLayout with a single column. This ensures that all the child
90 // views added get auto-expanded to fill the full width of the bubble.
91 views::GridLayout* CreateSingleColumnLayout(views::View* view, int width) {
92 views::GridLayout* layout = new views::GridLayout(view);
93 view->SetLayoutManager(layout);
95 views::ColumnSet* columns = layout->AddColumnSet(0);
96 columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 0,
97 views::GridLayout::FIXED, width, width);
98 return layout;
101 views::Link* CreateLink(const base::string16& link_text,
102 views::LinkListener* listener) {
103 views::Link* link_button = new views::Link(link_text);
104 link_button->SetHorizontalAlignment(gfx::ALIGN_LEFT);
105 link_button->SetUnderline(false);
106 link_button->set_listener(listener);
107 return link_button;
110 gfx::ImageSkia CreateSquarePlaceholderImage(int size) {
111 SkBitmap bitmap;
112 bitmap.allocPixels(SkImageInfo::MakeA8(size, size));
113 bitmap.eraseARGB(0, 0, 0, 0);
114 return gfx::ImageSkia::CreateFrom1xBitmap(bitmap);
117 bool HasAuthError(Profile* profile) {
118 const SigninErrorController* error =
119 SigninErrorControllerFactory::GetForProfile(profile);
120 return error && error->HasError();
123 std::string GetAuthErrorAccountId(Profile* profile) {
124 const SigninErrorController* error =
125 SigninErrorControllerFactory::GetForProfile(profile);
126 if (!error)
127 return std::string();
129 return error->error_account_id();
132 // BackgroundColorHoverButton -------------------------------------------------
134 // A custom button that allows for setting a background color when hovered over.
135 class BackgroundColorHoverButton : public views::LabelButton {
136 public:
137 BackgroundColorHoverButton(views::ButtonListener* listener,
138 const base::string16& text,
139 const gfx::ImageSkia& icon)
140 : views::LabelButton(listener, text) {
141 SetImageLabelSpacing(views::kItemLabelSpacing);
142 SetBorder(views::Border::CreateEmptyBorder(
143 0, views::kButtonHEdgeMarginNew, 0, views::kButtonHEdgeMarginNew));
144 SetMinSize(gfx::Size(0,
145 kButtonHeight + views::kRelatedControlVerticalSpacing));
146 SetImage(STATE_NORMAL, icon);
147 SetFocusable(true);
150 ~BackgroundColorHoverButton() override {}
152 private:
153 // views::LabelButton:
154 void OnPaint(gfx::Canvas* canvas) override {
155 if ((state() == STATE_PRESSED) ||
156 (state() == STATE_HOVERED)) {
157 canvas->DrawColor(GetNativeTheme()->GetSystemColor(
158 ui::NativeTheme::kColorId_ButtonHoverBackgroundColor));
160 LabelButton::OnPaint(canvas);
163 DISALLOW_COPY_AND_ASSIGN(BackgroundColorHoverButton);
166 // SizedContainer -------------------------------------------------
168 // A simple container view that takes an explicit preferred size.
169 class SizedContainer : public views::View {
170 public:
171 explicit SizedContainer(const gfx::Size& preferred_size)
172 : preferred_size_(preferred_size) {}
174 gfx::Size GetPreferredSize() const override { return preferred_size_; }
176 private:
177 gfx::Size preferred_size_;
180 } // namespace
182 // RightAlignedIconLabelButton -------------------------------------------------
184 // A custom LabelButton that has a centered text and right aligned icon.
185 class RightAlignedIconLabelButton : public views::LabelButton {
186 public:
187 RightAlignedIconLabelButton(views::ButtonListener* listener,
188 const base::string16& text)
189 : views::LabelButton(listener, text) {
192 protected:
193 void Layout() override {
194 // This layout trick keeps the text left-aligned and the icon right-aligned.
195 SetHorizontalAlignment(gfx::ALIGN_RIGHT);
196 views::LabelButton::Layout();
197 label()->SetHorizontalAlignment(gfx::ALIGN_CENTER);
200 private:
201 DISALLOW_COPY_AND_ASSIGN(RightAlignedIconLabelButton);
204 // EditableProfilePhoto -------------------------------------------------
206 // A custom Image control that shows a "change" button when moused over.
207 class EditableProfilePhoto : public views::LabelButton {
208 public:
209 EditableProfilePhoto(views::ButtonListener* listener,
210 const gfx::Image& icon,
211 bool is_editing_allowed,
212 const gfx::Rect& bounds)
213 : views::LabelButton(listener, base::string16()),
214 photo_overlay_(NULL) {
215 gfx::Image image = profiles::GetSizedAvatarIcon(
216 icon, true, kLargeImageSide, kLargeImageSide);
217 SetImage(views::LabelButton::STATE_NORMAL, *image.ToImageSkia());
218 SetBorder(views::Border::NullBorder());
219 SetBoundsRect(bounds);
221 // Calculate the circular mask that will be used to display the photo.
222 circular_mask_.addCircle(SkIntToScalar(bounds.width() / 2),
223 SkIntToScalar(bounds.height() / 2),
224 SkIntToScalar(bounds.width() / 2));
226 if (!is_editing_allowed) {
227 SetEnabled(false);
228 return;
231 set_notify_enter_exit_on_child(true);
233 // Photo overlay that appears when hovering over the button.
234 photo_overlay_ = new views::ImageView();
236 const SkColor kBackgroundColor = SkColorSetARGB(65, 255, 255, 255);
237 photo_overlay_->set_background(
238 views::Background::CreateSolidBackground(kBackgroundColor));
239 photo_overlay_->SetImage(*ui::ResourceBundle::GetSharedInstance().
240 GetImageSkiaNamed(IDR_ICON_PROFILES_EDIT_CAMERA));
242 photo_overlay_->SetSize(bounds.size());
243 photo_overlay_->SetVisible(false);
244 AddChildView(photo_overlay_);
247 void OnPaint(gfx::Canvas* canvas) override {
248 // Display the profile picture as a circle.
249 canvas->ClipPath(circular_mask_, true);
250 views::LabelButton::OnPaint(canvas);
253 void PaintChildren(const ui::PaintContext& context) override {
254 // Display any children (the "change photo" overlay) as a circle.
255 ui::ClipTransformRecorder clip_transform_recorder(context);
256 clip_transform_recorder.ClipPathWithAntiAliasing(circular_mask_);
257 View::PaintChildren(context);
260 private:
261 // views::CustomButton:
262 void StateChanged() override {
263 bool show_overlay =
264 (state() == STATE_PRESSED || state() == STATE_HOVERED || HasFocus());
265 if (photo_overlay_)
266 photo_overlay_->SetVisible(show_overlay);
269 void OnFocus() override {
270 views::LabelButton::OnFocus();
271 if (photo_overlay_)
272 photo_overlay_->SetVisible(true);
275 void OnBlur() override {
276 views::LabelButton::OnBlur();
277 // Don't hide the overlay if it's being shown as a result of a mouseover.
278 if (photo_overlay_ && state() != STATE_HOVERED)
279 photo_overlay_->SetVisible(false);
282 gfx::Path circular_mask_;
284 // Image that is shown when hovering over the image button. Can be NULL if
285 // the photo isn't allowed to be edited (e.g. for guest profiles).
286 views::ImageView* photo_overlay_;
288 DISALLOW_COPY_AND_ASSIGN(EditableProfilePhoto);
291 // EditableProfileName -------------------------------------------------
293 // A custom text control that turns into a textfield for editing when clicked.
294 class EditableProfileName : public RightAlignedIconLabelButton,
295 public views::ButtonListener {
296 public:
297 EditableProfileName(views::TextfieldController* controller,
298 const base::string16& text,
299 bool is_editing_allowed)
300 : RightAlignedIconLabelButton(this, text),
301 profile_name_textfield_(NULL) {
302 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
303 const gfx::FontList& medium_font_list =
304 rb->GetFontList(ui::ResourceBundle::MediumFont);
305 SetFontList(medium_font_list);
306 SetHorizontalAlignment(gfx::ALIGN_CENTER);
308 if (!is_editing_allowed) {
309 SetBorder(views::Border::CreateEmptyBorder(2, 0, 2, 0));
310 return;
313 // Show an "edit" pencil icon when hovering over. In the default state,
314 // we need to create an empty placeholder of the correct size, so that
315 // the text doesn't jump around when the hovered icon appears.
316 gfx::ImageSkia hover_image =
317 *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_EDIT_HOVER);
318 SetImage(STATE_NORMAL, CreateSquarePlaceholderImage(hover_image.width()));
319 SetImage(STATE_HOVERED, hover_image);
320 SetImage(STATE_PRESSED,
321 *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_EDIT_PRESSED));
322 // To center the text, we need to offest it by the width of the icon we
323 // are adding and its padding. We need to also add a small top/bottom
324 // padding to account for the textfield's border.
325 const int kIconTextLabelButtonSpacing = 5;
326 SetBorder(views::Border::CreateEmptyBorder(
327 2, hover_image.width() + kIconTextLabelButtonSpacing, 2, 0));
329 // Textfield that overlaps the button.
330 profile_name_textfield_ = new views::Textfield();
331 profile_name_textfield_->set_controller(controller);
332 profile_name_textfield_->SetFontList(medium_font_list);
333 profile_name_textfield_->SetHorizontalAlignment(gfx::ALIGN_CENTER);
335 profile_name_textfield_->SetVisible(false);
336 AddChildView(profile_name_textfield_);
339 views::Textfield* profile_name_textfield() {
340 return profile_name_textfield_;
343 // Hide the editable textfield to show the profile name button instead.
344 void ShowReadOnlyView() {
345 if (profile_name_textfield_)
346 profile_name_textfield_->SetVisible(false);
349 private:
350 // views::ButtonListener:
351 void ButtonPressed(views::Button* sender, const ui::Event& event) override {
352 if (profile_name_textfield_) {
353 profile_name_textfield_->SetVisible(true);
354 profile_name_textfield_->SetText(GetText());
355 profile_name_textfield_->SelectAll(false);
356 profile_name_textfield_->RequestFocus();
360 // views::LabelButton:
361 bool OnKeyReleased(const ui::KeyEvent& event) override {
362 // Override CustomButton's implementation, which presses the button when
363 // you press space and clicks it when you release space, as the space can be
364 // part of the new profile name typed in the textfield.
365 return false;
368 void Layout() override {
369 if (profile_name_textfield_)
370 profile_name_textfield_->SetBounds(0, 0, width(), height());
371 RightAlignedIconLabelButton::Layout();
374 void OnFocus() override {
375 RightAlignedIconLabelButton::OnFocus();
376 SetState(STATE_HOVERED);
379 void OnBlur() override {
380 RightAlignedIconLabelButton::OnBlur();
381 SetState(STATE_NORMAL);
384 // Textfield that is shown when editing the profile name. Can be NULL if
385 // the profile name isn't allowed to be edited (e.g. for guest profiles).
386 views::Textfield* profile_name_textfield_;
388 DISALLOW_COPY_AND_ASSIGN(EditableProfileName);
391 // A title card with one back button right aligned and one label center aligned.
392 class TitleCard : public views::View {
393 public:
394 TitleCard(const base::string16& message, views::ButtonListener* listener,
395 views::ImageButton** back_button) {
396 back_button_ = new views::ImageButton(listener);
397 back_button_->SetImageAlignment(views::ImageButton::ALIGN_LEFT,
398 views::ImageButton::ALIGN_MIDDLE);
399 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
400 back_button_->SetImage(views::ImageButton::STATE_NORMAL,
401 rb->GetImageSkiaNamed(IDR_BACK));
402 back_button_->SetImage(views::ImageButton::STATE_HOVERED,
403 rb->GetImageSkiaNamed(IDR_BACK_H));
404 back_button_->SetImage(views::ImageButton::STATE_PRESSED,
405 rb->GetImageSkiaNamed(IDR_BACK_P));
406 back_button_->SetImage(views::ImageButton::STATE_DISABLED,
407 rb->GetImageSkiaNamed(IDR_BACK_D));
408 back_button_->SetFocusable(true);
409 *back_button = back_button_;
411 title_label_ = new views::Label(message);
412 title_label_->SetHorizontalAlignment(gfx::ALIGN_CENTER);
413 const gfx::FontList& medium_font_list =
414 rb->GetFontList(ui::ResourceBundle::MediumFont);
415 title_label_->SetFontList(medium_font_list);
417 AddChildView(back_button_);
418 AddChildView(title_label_);
421 // Creates a new view that has the |title_card| with horizontal padding at the
422 // top, an edge-to-edge separator below, and the specified |view| at the
423 // bottom.
424 static views::View* AddPaddedTitleCard(views::View* view,
425 TitleCard* title_card,
426 int width) {
427 views::View* titled_view = new views::View();
428 views::GridLayout* layout = new views::GridLayout(titled_view);
429 titled_view->SetLayoutManager(layout);
431 // Column set 0 is a single column layout with horizontal padding at left
432 // and right, and column set 1 is a single column layout with no padding.
433 views::ColumnSet* columns = layout->AddColumnSet(0);
434 columns->AddPaddingColumn(1, views::kButtonHEdgeMarginNew);
435 int available_width = width - 2 * views::kButtonHEdgeMarginNew;
436 columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 0,
437 views::GridLayout::FIXED, available_width, available_width);
438 columns->AddPaddingColumn(1, views::kButtonHEdgeMarginNew);
439 layout->AddColumnSet(1)->AddColumn(views::GridLayout::FILL,
440 views::GridLayout::FILL, 0,views::GridLayout::FIXED, width, width);
442 layout->StartRowWithPadding(1, 0, 0, kVerticalSpacing);
443 layout->AddView(title_card);
444 layout->StartRowWithPadding(1, 1, 0, kVerticalSpacing);
445 layout->AddView(new views::Separator(views::Separator::HORIZONTAL));
447 layout->StartRow(1, 1);
448 layout->AddView(view);
450 return titled_view;
453 private:
454 void Layout() override {
455 int back_button_width = back_button_->GetPreferredSize().width();
456 back_button_->SetBounds(0, 0, back_button_width, height());
457 int label_padding = back_button_width + views::kButtonHEdgeMarginNew;
458 int label_width = width() - 2 * label_padding;
459 DCHECK_GT(label_width, 0);
460 title_label_->SetBounds(label_padding, 0, label_width, height());
463 gfx::Size GetPreferredSize() const override {
464 int height = std::max(title_label_->GetPreferredSize().height(),
465 back_button_->GetPreferredSize().height());
466 return gfx::Size(width(), height);
469 views::ImageButton* back_button_;
470 views::Label* title_label_;
472 DISALLOW_COPY_AND_ASSIGN(TitleCard);
475 // ProfileChooserView ---------------------------------------------------------
477 // static
478 ProfileChooserView* ProfileChooserView::profile_bubble_ = NULL;
479 bool ProfileChooserView::close_on_deactivate_for_testing_ = true;
481 // static
482 void ProfileChooserView::ShowBubble(
483 profiles::BubbleViewMode view_mode,
484 profiles::TutorialMode tutorial_mode,
485 const signin::ManageAccountsParams& manage_accounts_params,
486 views::View* anchor_view,
487 views::BubbleBorder::Arrow arrow,
488 views::BubbleBorder::BubbleAlignment border_alignment,
489 Browser* browser) {
490 // Don't start creating the view if it would be an empty fast user switcher.
491 // It has to happen here to prevent the view system from creating an empty
492 // container.
493 if (view_mode == profiles::BUBBLE_VIEW_MODE_FAST_PROFILE_CHOOSER &&
494 !profiles::HasProfileSwitchTargets(browser->profile())) {
495 return;
498 if (IsShowing()) {
499 if (tutorial_mode != profiles::TUTORIAL_MODE_NONE) {
500 profile_bubble_->tutorial_mode_ = tutorial_mode;
501 profile_bubble_->ShowView(view_mode, profile_bubble_->avatar_menu_.get());
503 return;
506 profile_bubble_ = new ProfileChooserView(anchor_view, arrow, browser,
507 view_mode, tutorial_mode, manage_accounts_params.service_type);
508 views::BubbleDelegateView::CreateBubble(profile_bubble_);
509 profile_bubble_->set_close_on_deactivate(close_on_deactivate_for_testing_);
510 profile_bubble_->SetAlignment(border_alignment);
511 profile_bubble_->GetWidget()->Show();
512 profile_bubble_->SetArrowPaintType(views::BubbleBorder::PAINT_NONE);
515 // static
516 bool ProfileChooserView::IsShowing() {
517 return profile_bubble_ != NULL;
520 // static
521 ProfileChooserView::ShowingType ProfileChooserView::IsShowingInBrowser(
522 const Browser* browser) {
523 if (profile_bubble_ == nullptr)
524 return IS_NOT_SHOWING;
526 if (profile_bubble_->browser_ == browser || browser == nullptr)
527 return IS_SHOWING;
529 return IS_SHOWING_IN_ANOTHER_BROWSER;
532 // static
533 void ProfileChooserView::Hide() {
534 if (IsShowing())
535 profile_bubble_->GetWidget()->Close();
538 ProfileChooserView::ProfileChooserView(views::View* anchor_view,
539 views::BubbleBorder::Arrow arrow,
540 Browser* browser,
541 profiles::BubbleViewMode view_mode,
542 profiles::TutorialMode tutorial_mode,
543 signin::GAIAServiceType service_type)
544 : BubbleDelegateView(anchor_view, arrow),
545 browser_(browser),
546 view_mode_(view_mode),
547 tutorial_mode_(tutorial_mode),
548 gaia_service_type_(service_type) {
549 // Reset the default margins inherited from the BubbleDelegateView.
550 // Add a small bottom inset so that the bubble's rounded corners show up.
551 set_margins(gfx::Insets(0, 0, 1, 0));
552 set_background(views::Background::CreateSolidBackground(
553 GetNativeTheme()->GetSystemColor(
554 ui::NativeTheme::kColorId_DialogBackground)));
555 ResetView();
557 avatar_menu_.reset(new AvatarMenu(
558 &g_browser_process->profile_manager()->GetProfileInfoCache(),
559 this,
560 browser_));
561 avatar_menu_->RebuildMenu();
563 ProfileOAuth2TokenService* oauth2_token_service =
564 ProfileOAuth2TokenServiceFactory::GetForProfile(browser_->profile());
565 if (oauth2_token_service)
566 oauth2_token_service->AddObserver(this);
569 ProfileChooserView::~ProfileChooserView() {
570 ProfileOAuth2TokenService* oauth2_token_service =
571 ProfileOAuth2TokenServiceFactory::GetForProfile(browser_->profile());
572 if (oauth2_token_service)
573 oauth2_token_service->RemoveObserver(this);
576 void ProfileChooserView::ResetView() {
577 open_other_profile_indexes_map_.clear();
578 delete_account_button_map_.clear();
579 reauth_account_button_map_.clear();
580 manage_accounts_link_ = NULL;
581 signin_current_profile_link_ = NULL;
582 auth_error_email_button_ = NULL;
583 current_profile_photo_ = NULL;
584 current_profile_name_ = NULL;
585 users_button_ = NULL;
586 go_incognito_button_ = NULL;
587 lock_button_ = NULL;
588 add_account_link_ = NULL;
589 gaia_signin_cancel_button_ = NULL;
590 remove_account_button_ = NULL;
591 account_removal_cancel_button_ = NULL;
592 add_person_button_ = NULL;
593 disconnect_button_ = NULL;
594 switch_user_cancel_button_ = NULL;
595 tutorial_sync_settings_ok_button_ = NULL;
596 tutorial_close_button_ = NULL;
597 tutorial_sync_settings_link_ = NULL;
598 tutorial_see_whats_new_button_ = NULL;
599 tutorial_not_you_link_ = NULL;
600 tutorial_learn_more_link_ = NULL;
603 void ProfileChooserView::Init() {
604 // If view mode is PROFILE_CHOOSER but there is an auth error, force
605 // ACCOUNT_MANAGEMENT mode.
606 if (IsProfileChooser(view_mode_) &&
607 HasAuthError(browser_->profile()) &&
608 switches::IsEnableAccountConsistency() &&
609 avatar_menu_->GetItemAt(avatar_menu_->GetActiveProfileIndex()).
610 signed_in) {
611 view_mode_ = profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT;
614 // The arrow keys can be used to tab between items.
615 AddAccelerator(ui::Accelerator(ui::VKEY_DOWN, ui::EF_NONE));
616 AddAccelerator(ui::Accelerator(ui::VKEY_UP, ui::EF_NONE));
618 ShowView(view_mode_, avatar_menu_.get());
621 void ProfileChooserView::OnAvatarMenuChanged(
622 AvatarMenu* avatar_menu) {
623 if (IsProfileChooser(view_mode_) ||
624 view_mode_ == profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT) {
625 // Refresh the view with the new menu. We can't just update the local copy
626 // as this may have been triggered by a sign out action, in which case
627 // the view is being destroyed.
628 ShowView(view_mode_, avatar_menu);
632 void ProfileChooserView::OnRefreshTokenAvailable(
633 const std::string& account_id) {
634 if (view_mode_ == profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT ||
635 view_mode_ == profiles::BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT ||
636 view_mode_ == profiles::BUBBLE_VIEW_MODE_GAIA_REAUTH) {
637 // The account management UI is only available through the
638 // --enable-account-consistency flag.
639 ShowView(switches::IsEnableAccountConsistency() ?
640 profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT :
641 profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER, avatar_menu_.get());
645 void ProfileChooserView::OnRefreshTokenRevoked(const std::string& account_id) {
646 // Refresh the account management view when an account is removed from the
647 // profile.
648 if (view_mode_ == profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT)
649 ShowView(profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT, avatar_menu_.get());
652 void ProfileChooserView::ShowView(profiles::BubbleViewMode view_to_display,
653 AvatarMenu* avatar_menu) {
654 // The account management view should only be displayed if the active profile
655 // is signed in.
656 if (view_to_display == profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT) {
657 DCHECK(switches::IsEnableAccountConsistency());
658 const AvatarMenu::Item& active_item = avatar_menu->GetItemAt(
659 avatar_menu->GetActiveProfileIndex());
660 DCHECK(active_item.signed_in);
663 if (browser_->profile()->IsSupervised() &&
664 (view_to_display == profiles::BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT ||
665 view_to_display == profiles::BUBBLE_VIEW_MODE_ACCOUNT_REMOVAL)) {
666 LOG(WARNING) << "Supervised user attempted to add/remove account";
667 return;
670 ResetView();
671 RemoveAllChildViews(true);
672 view_mode_ = view_to_display;
674 views::GridLayout* layout;
675 views::View* sub_view;
676 switch (view_mode_) {
677 case profiles::BUBBLE_VIEW_MODE_GAIA_SIGNIN:
678 case profiles::BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT:
679 case profiles::BUBBLE_VIEW_MODE_GAIA_REAUTH:
680 layout = CreateSingleColumnLayout(this, kFixedGaiaViewWidth);
681 sub_view = CreateGaiaSigninView();
682 break;
683 case profiles::BUBBLE_VIEW_MODE_ACCOUNT_REMOVAL:
684 layout = CreateSingleColumnLayout(this, kFixedAccountRemovalViewWidth);
685 sub_view = CreateAccountRemovalView();
686 break;
687 case profiles::BUBBLE_VIEW_MODE_SWITCH_USER:
688 layout = CreateSingleColumnLayout(this, kFixedSwitchUserViewWidth);
689 sub_view = CreateSwitchUserView();
690 ProfileMetrics::LogProfileNewAvatarMenuNotYou(
691 ProfileMetrics::PROFILE_AVATAR_MENU_NOT_YOU_VIEW);
692 break;
693 default:
694 layout = CreateSingleColumnLayout(this, kFixedMenuWidth);
695 sub_view = CreateProfileChooserView(avatar_menu);
697 // Clears tutorial mode for all non-profile-chooser views.
698 if (view_mode_ != profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER)
699 tutorial_mode_ = profiles::TUTORIAL_MODE_NONE;
701 if (view_mode_ == profiles::BUBBLE_VIEW_MODE_GAIA_SIGNIN ||
702 view_mode_ == profiles::BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT ||
703 view_mode_ == profiles::BUBBLE_VIEW_MODE_GAIA_REAUTH ||
704 tutorial_mode_ == profiles::TUTORIAL_MODE_CONFIRM_SIGNIN) {
705 profile_bubble_->set_close_on_deactivate(false);
706 } else {
707 profile_bubble_->set_close_on_deactivate(close_on_deactivate_for_testing_);
710 layout->StartRow(1, 0);
711 layout->AddView(sub_view);
712 Layout();
713 if (GetBubbleFrameView())
714 SizeToContents();
717 void ProfileChooserView::WindowClosing() {
718 DCHECK_EQ(profile_bubble_, this);
719 profile_bubble_ = NULL;
721 if (tutorial_mode_ == profiles::TUTORIAL_MODE_CONFIRM_SIGNIN) {
722 LoginUIServiceFactory::GetForProfile(browser_->profile())->
723 SyncConfirmationUIClosed(false /* configure_sync_first */);
727 bool ProfileChooserView::AcceleratorPressed(
728 const ui::Accelerator& accelerator) {
729 if (accelerator.key_code() != ui::VKEY_DOWN &&
730 accelerator.key_code() != ui::VKEY_UP)
731 return BubbleDelegateView::AcceleratorPressed(accelerator);
732 // Move the focus up or down.
733 GetFocusManager()->AdvanceFocus(accelerator.key_code() != ui::VKEY_DOWN);
734 return true;
737 bool ProfileChooserView::HandleContextMenu(
738 const content::ContextMenuParams& params) {
739 // Suppresses the context menu because some features, such as inspecting
740 // elements, are not appropriate in a bubble.
741 return true;
744 void ProfileChooserView::ButtonPressed(views::Button* sender,
745 const ui::Event& event) {
746 if (sender == users_button_) {
747 // If this is a guest session, close all the guest browser windows.
748 if (browser_->profile()->IsGuestSession()) {
749 profiles::CloseGuestProfileWindows();
750 } else {
751 UserManager::Show(base::FilePath(),
752 profiles::USER_MANAGER_NO_TUTORIAL,
753 profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION);
755 PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_OPEN_USER_MANAGER);
756 } else if (sender == go_incognito_button_) {
757 DCHECK(ShouldShowGoIncognito());
758 chrome::NewIncognitoWindow(browser_);
759 PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_GO_INCOGNITO);
760 } else if (sender == lock_button_) {
761 profiles::LockProfile(browser_->profile());
762 PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_LOCK);
763 } else if (sender == auth_error_email_button_) {
764 ShowView(profiles::BUBBLE_VIEW_MODE_GAIA_REAUTH, avatar_menu_.get());
765 } else if (sender == tutorial_sync_settings_ok_button_) {
766 LoginUIServiceFactory::GetForProfile(browser_->profile())->
767 SyncConfirmationUIClosed(false /* configure_sync_first */);
768 DismissTutorial();
769 ProfileMetrics::LogProfileNewAvatarMenuSignin(
770 ProfileMetrics::PROFILE_AVATAR_MENU_SIGNIN_OK);
771 } else if (sender == tutorial_close_button_) {
772 DCHECK(tutorial_mode_ != profiles::TUTORIAL_MODE_NONE &&
773 tutorial_mode_ != profiles::TUTORIAL_MODE_CONFIRM_SIGNIN);
774 DismissTutorial();
775 } else if (sender == tutorial_see_whats_new_button_) {
776 ProfileMetrics::LogProfileNewAvatarMenuUpgrade(
777 ProfileMetrics::PROFILE_AVATAR_MENU_UPGRADE_WHATS_NEW);
778 UserManager::Show(base::FilePath(),
779 profiles::USER_MANAGER_TUTORIAL_OVERVIEW,
780 profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION);
781 } else if (sender == remove_account_button_) {
782 RemoveAccount();
783 } else if (sender == account_removal_cancel_button_) {
784 account_id_to_remove_.clear();
785 ShowView(profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT, avatar_menu_.get());
786 } else if (sender == gaia_signin_cancel_button_) {
787 // The account management view is only available with the
788 // --enable-account-consistency flag.
789 bool account_management_available =
790 SigninManagerFactory::GetForProfile(browser_->profile())->
791 IsAuthenticated() &&
792 switches::IsEnableAccountConsistency();
793 ShowView(account_management_available ?
794 profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT :
795 profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER, avatar_menu_.get());
796 } else if (sender == current_profile_photo_) {
797 avatar_menu_->EditProfile(avatar_menu_->GetActiveProfileIndex());
798 PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_EDIT_IMAGE);
799 } else if (sender == signin_current_profile_link_) {
800 ShowView(profiles::BUBBLE_VIEW_MODE_GAIA_SIGNIN, avatar_menu_.get());
801 } else if (sender == add_person_button_) {
802 ProfileMetrics::LogProfileNewAvatarMenuNotYou(
803 ProfileMetrics::PROFILE_AVATAR_MENU_NOT_YOU_ADD_PERSON);
804 UserManager::Show(base::FilePath(),
805 profiles::USER_MANAGER_NO_TUTORIAL,
806 profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION);
807 } else if (sender == disconnect_button_) {
808 ProfileMetrics::LogProfileNewAvatarMenuNotYou(
809 ProfileMetrics::PROFILE_AVATAR_MENU_NOT_YOU_DISCONNECT);
810 chrome::ShowSettings(browser_);
811 } else if (sender == switch_user_cancel_button_) {
812 ShowView(profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER, avatar_menu_.get());
813 ProfileMetrics::LogProfileNewAvatarMenuNotYou(
814 ProfileMetrics::PROFILE_AVATAR_MENU_NOT_YOU_BACK);
815 } else {
816 // Either one of the "other profiles", or one of the profile accounts
817 // buttons was pressed.
818 ButtonIndexes::const_iterator profile_match =
819 open_other_profile_indexes_map_.find(sender);
820 if (profile_match != open_other_profile_indexes_map_.end()) {
821 avatar_menu_->SwitchToProfile(
822 profile_match->second,
823 ui::DispositionFromEventFlags(event.flags()) == NEW_WINDOW,
824 ProfileMetrics::SWITCH_PROFILE_ICON);
825 } else {
826 // This was a profile accounts button.
827 AccountButtonIndexes::const_iterator account_match =
828 delete_account_button_map_.find(sender);
829 if (account_match != delete_account_button_map_.end()) {
830 account_id_to_remove_ = account_match->second;
831 ShowView(profiles::BUBBLE_VIEW_MODE_ACCOUNT_REMOVAL,
832 avatar_menu_.get());
833 } else {
834 account_match = reauth_account_button_map_.find(sender);
835 DCHECK(account_match != reauth_account_button_map_.end());
836 ShowView(profiles::BUBBLE_VIEW_MODE_GAIA_REAUTH, avatar_menu_.get());
842 void ProfileChooserView::RemoveAccount() {
843 DCHECK(!account_id_to_remove_.empty());
844 MutableProfileOAuth2TokenService* oauth2_token_service =
845 ProfileOAuth2TokenServiceFactory::GetPlatformSpecificForProfile(
846 browser_->profile());
847 if (oauth2_token_service) {
848 oauth2_token_service->RevokeCredentials(account_id_to_remove_);
849 PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_REMOVE_ACCT);
851 account_id_to_remove_.clear();
853 ShowView(profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT, avatar_menu_.get());
856 void ProfileChooserView::LinkClicked(views::Link* sender, int event_flags) {
857 if (sender == manage_accounts_link_) {
858 // This link can either mean show/hide the account management view,
859 // depending on which view it is displayed. ShowView() will DCHECK if
860 // the account management view is displayed for non signed-in users.
861 ShowView(
862 view_mode_ == profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT ?
863 profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER :
864 profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT,
865 avatar_menu_.get());
866 } else if (sender == add_account_link_) {
867 ShowView(profiles::BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT, avatar_menu_.get());
868 PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_ADD_ACCT);
869 } else if (sender == tutorial_sync_settings_link_) {
870 LoginUIServiceFactory::GetForProfile(browser_->profile())->
871 SyncConfirmationUIClosed(true /* configure_sync_first */);
872 tutorial_mode_ = profiles::TUTORIAL_MODE_NONE;
873 ProfileMetrics::LogProfileNewAvatarMenuSignin(
874 ProfileMetrics::PROFILE_AVATAR_MENU_SIGNIN_SETTINGS);
875 } else if (sender == tutorial_not_you_link_) {
876 ProfileMetrics::LogProfileNewAvatarMenuUpgrade(
877 ProfileMetrics::PROFILE_AVATAR_MENU_UPGRADE_NOT_YOU);
878 ShowView(profiles::BUBBLE_VIEW_MODE_SWITCH_USER, avatar_menu_.get());
879 } else {
880 DCHECK(sender == tutorial_learn_more_link_);
881 signin_ui_util::ShowSigninErrorLearnMorePage(browser_->profile());
885 void ProfileChooserView::StyledLabelLinkClicked(
886 const gfx::Range& range, int event_flags) {
887 chrome::ShowSettings(browser_);
890 bool ProfileChooserView::HandleKeyEvent(views::Textfield* sender,
891 const ui::KeyEvent& key_event) {
892 views::Textfield* name_textfield =
893 current_profile_name_->profile_name_textfield();
894 DCHECK(sender == name_textfield);
896 if (key_event.key_code() == ui::VKEY_RETURN ||
897 key_event.key_code() == ui::VKEY_TAB) {
898 // Pressing Tab/Enter commits the new profile name, unless it's empty.
899 base::string16 new_profile_name = name_textfield->text();
900 base::TrimWhitespace(new_profile_name, base::TRIM_ALL, &new_profile_name);
901 if (new_profile_name.empty())
902 return true;
904 const AvatarMenu::Item& active_item = avatar_menu_->GetItemAt(
905 avatar_menu_->GetActiveProfileIndex());
906 Profile* profile = g_browser_process->profile_manager()->GetProfile(
907 active_item.profile_path);
908 DCHECK(profile);
910 if (profile->IsLegacySupervised())
911 return true;
913 profiles::UpdateProfileName(profile, new_profile_name);
914 PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_EDIT_NAME);
915 current_profile_name_->ShowReadOnlyView();
916 return true;
918 return false;
921 void ProfileChooserView::PopulateCompleteProfileChooserView(
922 views::GridLayout* layout,
923 AvatarMenu* avatar_menu) {
924 // Separate items into active and alternatives.
925 Indexes other_profiles;
926 views::View* tutorial_view = NULL;
927 views::View* current_profile_view = NULL;
928 views::View* current_profile_accounts = NULL;
929 views::View* option_buttons_view = NULL;
930 for (size_t i = 0; i < avatar_menu->GetNumberOfItems(); ++i) {
931 const AvatarMenu::Item& item = avatar_menu->GetItemAt(i);
932 if (item.active) {
933 option_buttons_view = CreateOptionsView(
934 item.signed_in && profiles::IsLockAvailable(browser_->profile()));
935 current_profile_view = CreateCurrentProfileView(item, false);
936 if (IsProfileChooser(view_mode_)) {
937 tutorial_view = CreateTutorialViewIfNeeded(item);
938 } else {
939 current_profile_accounts = CreateCurrentProfileAccountsView(item);
941 } else {
942 other_profiles.push_back(i);
946 if (tutorial_view) {
947 // TODO(mlerman): update UMA stats for the new tutorial.
948 layout->StartRow(1, 0);
949 layout->AddView(tutorial_view);
950 } else {
951 tutorial_mode_ = profiles::TUTORIAL_MODE_NONE;
954 if (!current_profile_view) {
955 // Guest windows don't have an active profile.
956 current_profile_view = CreateGuestProfileView();
957 option_buttons_view = CreateOptionsView(false);
960 layout->StartRow(1, 0);
961 layout->AddView(current_profile_view);
963 if (!IsProfileChooser(view_mode_)) {
964 DCHECK(current_profile_accounts);
965 layout->StartRow(0, 0);
966 layout->AddView(new views::Separator(views::Separator::HORIZONTAL));
967 layout->StartRow(1, 0);
968 layout->AddView(current_profile_accounts);
971 if (browser_->profile()->IsSupervised()) {
972 layout->StartRow(0, 0);
973 layout->AddView(new views::Separator(views::Separator::HORIZONTAL));
974 layout->StartRow(1, 0);
975 layout->AddView(CreateSupervisedUserDisclaimerView());
978 layout->StartRow(0, 0);
979 layout->AddView(new views::Separator(views::Separator::HORIZONTAL));
981 if (option_buttons_view) {
982 layout->StartRow(0, 0);
983 layout->AddView(option_buttons_view);
987 void ProfileChooserView::PopulateMinimalProfileChooserView(
988 views::GridLayout* layout,
989 AvatarMenu* avatar_menu) {
990 Indexes other_profiles;
991 for (size_t i = 0; i < avatar_menu->GetNumberOfItems(); ++i) {
992 const AvatarMenu::Item& item = avatar_menu->GetItemAt(i);
993 if (!item.active) {
994 other_profiles.push_back(i);
998 layout->StartRow(1, 0);
999 layout->AddView(CreateOtherProfilesView(other_profiles));
1002 views::View* ProfileChooserView::CreateProfileChooserView(
1003 AvatarMenu* avatar_menu) {
1004 views::View* view = new views::View();
1005 views::GridLayout* layout = CreateSingleColumnLayout(view, kFixedMenuWidth);
1007 if (view_mode_ == profiles::BUBBLE_VIEW_MODE_FAST_PROFILE_CHOOSER) {
1008 PopulateMinimalProfileChooserView(layout, avatar_menu);
1009 // The user is using right-click switching, no need to tell them about it.
1010 PrefService* local_state = g_browser_process->local_state();
1011 local_state->SetBoolean(
1012 prefs::kProfileAvatarRightClickTutorialDismissed, true);
1013 } else {
1014 PopulateCompleteProfileChooserView(layout, avatar_menu);
1017 return view;
1020 void ProfileChooserView::DismissTutorial() {
1021 // Never shows the upgrade tutorial again if manually closed.
1022 if (tutorial_mode_ == profiles::TUTORIAL_MODE_WELCOME_UPGRADE) {
1023 browser_->profile()->GetPrefs()->SetInteger(
1024 prefs::kProfileAvatarTutorialShown,
1025 signin_ui_util::kUpgradeWelcomeTutorialShowMax + 1);
1028 if (tutorial_mode_ == profiles::TUTORIAL_MODE_RIGHT_CLICK_SWITCHING) {
1029 PrefService* local_state = g_browser_process->local_state();
1030 local_state->SetBoolean(
1031 prefs::kProfileAvatarRightClickTutorialDismissed, true);
1034 tutorial_mode_ = profiles::TUTORIAL_MODE_NONE;
1035 ShowView(profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER, avatar_menu_.get());
1038 views::View* ProfileChooserView::CreateTutorialViewIfNeeded(
1039 const AvatarMenu::Item& item) {
1040 if (tutorial_mode_ == profiles::TUTORIAL_MODE_CONFIRM_SIGNIN)
1041 return CreateSigninConfirmationView();
1043 if (tutorial_mode_ == profiles::TUTORIAL_MODE_SHOW_ERROR)
1044 return CreateSigninErrorView();
1046 if (profiles::ShouldShowWelcomeUpgradeTutorial(
1047 browser_->profile(), tutorial_mode_)) {
1048 if (tutorial_mode_ != profiles::TUTORIAL_MODE_WELCOME_UPGRADE) {
1049 Profile* profile = browser_->profile();
1050 const int show_count = profile->GetPrefs()->GetInteger(
1051 prefs::kProfileAvatarTutorialShown);
1052 profile->GetPrefs()->SetInteger(
1053 prefs::kProfileAvatarTutorialShown, show_count + 1);
1056 return CreateWelcomeUpgradeTutorialView(item);
1059 if (profiles::ShouldShowRightClickTutorial(browser_->profile()))
1060 return CreateRightClickTutorialView();
1062 return nullptr;
1065 views::View* ProfileChooserView::CreateTutorialView(
1066 profiles::TutorialMode tutorial_mode,
1067 const base::string16& title_text,
1068 const base::string16& content_text,
1069 const base::string16& link_text,
1070 const base::string16& button_text,
1071 bool stack_button,
1072 views::Link** link,
1073 views::LabelButton** button,
1074 views::ImageButton** close_button) {
1075 tutorial_mode_ = tutorial_mode;
1077 views::View* view = new views::View();
1078 view->set_background(views::Background::CreateSolidBackground(
1079 profiles::kAvatarTutorialBackgroundColor));
1080 views::GridLayout* layout = CreateSingleColumnLayout(view,
1081 kFixedMenuWidth - 2 * views::kButtonHEdgeMarginNew);
1082 // Creates a second column set for buttons and links.
1083 views::ColumnSet* button_columns = layout->AddColumnSet(1);
1084 button_columns->AddColumn(views::GridLayout::LEADING,
1085 views::GridLayout::CENTER, 0, views::GridLayout::USE_PREF, 0, 0);
1086 button_columns->AddPaddingColumn(
1087 1, views::kUnrelatedControlHorizontalSpacing);
1088 button_columns->AddColumn(views::GridLayout::TRAILING,
1089 views::GridLayout::CENTER, 0, views::GridLayout::USE_PREF, 0, 0);
1090 layout->SetInsets(views::kButtonVEdgeMarginNew,
1091 views::kButtonHEdgeMarginNew,
1092 views::kButtonVEdgeMarginNew,
1093 views::kButtonHEdgeMarginNew);
1095 // Adds title and close button if needed.
1096 views::Label* title_label = new views::Label(title_text);
1097 title_label->SetMultiLine(true);
1098 title_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
1099 title_label->SetAutoColorReadabilityEnabled(false);
1100 title_label->SetEnabledColor(SK_ColorWHITE);
1101 title_label->SetFontList(ui::ResourceBundle::GetSharedInstance().GetFontList(
1102 ui::ResourceBundle::MediumFont));
1104 if (close_button) {
1105 layout->StartRow(1, 1);
1106 layout->AddView(title_label);
1107 *close_button = new views::ImageButton(this);
1108 (*close_button)->SetImageAlignment(views::ImageButton::ALIGN_RIGHT,
1109 views::ImageButton::ALIGN_MIDDLE);
1110 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
1111 (*close_button)->SetImage(views::ImageButton::STATE_NORMAL,
1112 rb->GetImageSkiaNamed(IDR_CLOSE_1));
1113 (*close_button)->SetImage(views::ImageButton::STATE_HOVERED,
1114 rb->GetImageSkiaNamed(IDR_CLOSE_1_H));
1115 (*close_button)->SetImage(views::ImageButton::STATE_PRESSED,
1116 rb->GetImageSkiaNamed(IDR_CLOSE_1_P));
1117 layout->AddView(*close_button);
1118 } else {
1119 layout->StartRow(1, 0);
1120 layout->AddView(title_label);
1123 // Adds body content.
1124 views::Label* content_label = new views::Label(content_text);
1125 content_label->SetMultiLine(true);
1126 content_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
1127 content_label->SetAutoColorReadabilityEnabled(false);
1128 content_label->SetEnabledColor(profiles::kAvatarTutorialContentTextColor);
1129 layout->StartRowWithPadding(1, 0, 0, views::kRelatedControlVerticalSpacing);
1130 layout->AddView(content_label);
1132 // Adds links and buttons.
1133 bool has_button = !button_text.empty();
1134 if (has_button) {
1135 *button = new views::LabelButton(this, button_text);
1136 (*button)->SetHorizontalAlignment(gfx::ALIGN_CENTER);
1137 (*button)->SetStyle(views::Button::STYLE_BUTTON);
1140 bool has_link = !link_text.empty();
1141 if (has_link) {
1142 *link = CreateLink(link_text, this);
1143 (*link)->SetHorizontalAlignment(gfx::ALIGN_LEFT);
1144 (*link)->SetAutoColorReadabilityEnabled(false);
1145 (*link)->SetEnabledColor(SK_ColorWHITE);
1148 if (stack_button) {
1149 DCHECK(has_button);
1150 layout->StartRowWithPadding(
1151 1, 0, 0, views::kUnrelatedControlVerticalSpacing);
1152 layout->AddView(*button);
1153 if (has_link) {
1154 layout->StartRowWithPadding(
1155 1, 0, 0, views::kRelatedControlVerticalSpacing);
1156 (*link)->SetHorizontalAlignment(gfx::ALIGN_CENTER);
1157 layout->AddView(*link);
1159 } else {
1160 DCHECK(has_link || has_button);
1161 layout->StartRowWithPadding(
1162 1, 1, 0, views::kUnrelatedControlVerticalSpacing);
1163 if (has_link)
1164 layout->AddView(*link);
1165 else
1166 layout->SkipColumns(1);
1167 if (has_button)
1168 layout->AddView(*button);
1169 else
1170 layout->SkipColumns(1);
1173 return view;
1176 views::View* ProfileChooserView::CreateCurrentProfileView(
1177 const AvatarMenu::Item& avatar_item,
1178 bool is_guest) {
1179 views::View* view = new views::View();
1180 int column_width = kFixedMenuWidth - 2 * views::kButtonHEdgeMarginNew;
1181 views::GridLayout* layout = CreateSingleColumnLayout(view, column_width);
1182 layout->SetInsets(views::kButtonVEdgeMarginNew,
1183 views::kButtonHEdgeMarginNew,
1184 views::kUnrelatedControlVerticalSpacing,
1185 views::kButtonHEdgeMarginNew);
1187 // Profile icon, centered.
1188 int x_offset = (column_width - kLargeImageSide) / 2;
1189 current_profile_photo_ = new EditableProfilePhoto(
1190 this, avatar_item.icon, !is_guest,
1191 gfx::Rect(x_offset, 0, kLargeImageSide, kLargeImageSide));
1192 SizedContainer* profile_icon_container =
1193 new SizedContainer(gfx::Size(column_width, kLargeImageSide));
1194 profile_icon_container->AddChildView(current_profile_photo_);
1196 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
1197 if (browser_->profile()->IsSupervised()) {
1198 views::ImageView* supervised_icon = new views::ImageView();
1199 int image_id = browser_->profile()->IsChild()
1200 ? IDR_ICON_PROFILES_MENU_CHILD
1201 : IDR_ICON_PROFILES_MENU_LEGACY_SUPERVISED;
1202 supervised_icon->SetImage(rb->GetImageSkiaNamed(image_id));
1203 gfx::Size preferred_size = supervised_icon->GetPreferredSize();
1204 gfx::Rect parent_bounds = current_profile_photo_->bounds();
1205 supervised_icon->SetBounds(
1206 parent_bounds.right() - preferred_size.width(),
1207 parent_bounds.bottom() - preferred_size.height(),
1208 preferred_size.width(),
1209 preferred_size.height());
1210 profile_icon_container->AddChildView(supervised_icon);
1213 layout->StartRow(1, 0);
1214 layout->AddView(profile_icon_container);
1216 // Profile name, centered.
1217 bool editing_allowed = !is_guest &&
1218 !browser_->profile()->IsLegacySupervised();
1219 current_profile_name_ = new EditableProfileName(
1220 this,
1221 profiles::GetAvatarNameForProfile(browser_->profile()->GetPath()),
1222 editing_allowed);
1223 layout->StartRowWithPadding(1, 0, 0,
1224 views::kRelatedControlSmallVerticalSpacing);
1225 layout->StartRow(1, 0);
1226 layout->AddView(current_profile_name_);
1228 if (is_guest)
1229 return view;
1231 // The available links depend on the type of profile that is active.
1232 if (avatar_item.signed_in) {
1233 layout->StartRow(1, 0);
1234 if (switches::IsEnableAccountConsistency()) {
1235 base::string16 link_title = l10n_util::GetStringUTF16(
1236 IsProfileChooser(view_mode_) ?
1237 IDS_PROFILES_PROFILE_MANAGE_ACCOUNTS_BUTTON :
1238 IDS_PROFILES_PROFILE_HIDE_MANAGE_ACCOUNTS_BUTTON);
1239 manage_accounts_link_ = CreateLink(link_title, this);
1240 manage_accounts_link_->SetHorizontalAlignment(gfx::ALIGN_CENTER);
1241 layout->AddView(manage_accounts_link_);
1242 } else {
1243 // Badge the email address if there's an authentication error.
1244 if (HasAuthError(browser_->profile())) {
1245 const gfx::ImageSkia warning_image = *rb->GetImageNamed(
1246 IDR_ICON_PROFILES_ACCOUNT_BUTTON_ERROR).ToImageSkia();
1247 auth_error_email_button_ =
1248 new RightAlignedIconLabelButton(this, avatar_item.username);
1249 auth_error_email_button_->SetElideBehavior(gfx::ELIDE_EMAIL);
1250 auth_error_email_button_->SetImage(
1251 views::LabelButton::STATE_NORMAL, warning_image);
1252 auth_error_email_button_->SetTextColor(
1253 views::LabelButton::STATE_NORMAL,
1254 views::Link::GetDefaultEnabledColor());
1255 auth_error_email_button_->SetFocusable(true);
1256 gfx::Insets insets = views::LabelButtonBorder::GetDefaultInsetsForStyle(
1257 views::Button::STYLE_TEXTBUTTON);
1258 auth_error_email_button_->SetBorder(views::Border::CreateEmptyBorder(
1259 insets.top(), insets.left(), insets.bottom(), insets.right()));
1260 layout->AddView(auth_error_email_button_);
1261 } else {
1262 // Add a small padding between the email button and the profile name.
1263 layout->StartRowWithPadding(1, 0, 0, 2);
1264 views::Label* email_label = new views::Label(avatar_item.username);
1265 email_label->SetElideBehavior(gfx::ELIDE_EMAIL);
1266 email_label->SetEnabled(false);
1267 layout->AddView(email_label);
1270 } else {
1271 SigninManagerBase* signin_manager = SigninManagerFactory::GetForProfile(
1272 browser_->profile()->GetOriginalProfile());
1273 if (signin_manager->IsSigninAllowed()) {
1274 views::Label* promo = new views::Label(
1275 l10n_util::GetStringUTF16(IDS_PROFILES_SIGNIN_PROMO));
1276 promo->SetMultiLine(true);
1277 promo->SetHorizontalAlignment(gfx::ALIGN_LEFT);
1278 layout->StartRowWithPadding(1, 0, 0,
1279 views::kRelatedControlSmallVerticalSpacing);
1280 layout->StartRow(1, 0);
1281 layout->AddView(promo);
1283 signin_current_profile_link_ = new views::BlueButton(
1284 this, l10n_util::GetStringFUTF16(IDS_SYNC_START_SYNC_BUTTON_LABEL,
1285 l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME)));
1286 layout->StartRowWithPadding(1, 0, 0,
1287 views::kRelatedControlVerticalSpacing);
1288 layout->StartRow(1, 0);
1289 layout->AddView(signin_current_profile_link_);
1293 return view;
1296 views::View* ProfileChooserView::CreateGuestProfileView() {
1297 gfx::Image guest_icon =
1298 ui::ResourceBundle::GetSharedInstance().GetImageNamed(
1299 profiles::GetPlaceholderAvatarIconResourceID());
1300 AvatarMenu::Item guest_avatar_item(0, 0, guest_icon);
1301 guest_avatar_item.active = true;
1302 guest_avatar_item.name = l10n_util::GetStringUTF16(
1303 IDS_PROFILES_GUEST_PROFILE_NAME);
1304 guest_avatar_item.signed_in = false;
1306 return CreateCurrentProfileView(guest_avatar_item, true);
1309 views::View* ProfileChooserView::CreateOtherProfilesView(
1310 const Indexes& avatars_to_show) {
1311 views::View* view = new views::View();
1312 views::GridLayout* layout = CreateSingleColumnLayout(view, kFixedMenuWidth);
1314 for (size_t index : avatars_to_show) {
1315 const AvatarMenu::Item& item = avatar_menu_->GetItemAt(index);
1316 const int kSmallImageSide = 32;
1318 // Use the low-res, small default avatars in the fast user switcher, like
1319 // we do in the menu bar.
1320 gfx::Image item_icon;
1321 bool is_rectangle;
1322 AvatarMenu::GetImageForMenuButton(
1323 item.profile_path, &item_icon, &is_rectangle);
1325 gfx::Image image = profiles::GetSizedAvatarIcon(
1326 item_icon, true, kSmallImageSide, kSmallImageSide);
1328 views::LabelButton* button = new BackgroundColorHoverButton(
1329 this,
1330 profiles::GetProfileSwitcherTextForItem(item),
1331 *image.ToImageSkia());
1332 open_other_profile_indexes_map_[button] = index;
1334 layout->StartRow(1, 0);
1335 layout->AddView(new views::Separator(views::Separator::HORIZONTAL));
1336 layout->StartRow(1, 0);
1337 layout->AddView(button);
1340 return view;
1343 views::View* ProfileChooserView::CreateOptionsView(bool display_lock) {
1344 views::View* view = new views::View();
1345 views::GridLayout* layout = CreateSingleColumnLayout(view, kFixedMenuWidth);
1347 base::string16 text = browser_->profile()->IsGuestSession() ?
1348 l10n_util::GetStringUTF16(IDS_PROFILES_EXIT_GUEST) :
1349 l10n_util::GetStringUTF16(IDS_PROFILES_SWITCH_USERS_BUTTON);
1350 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
1351 users_button_ = new BackgroundColorHoverButton(
1352 this,
1353 text,
1354 *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_AVATAR));
1355 layout->StartRow(1, 0);
1356 layout->AddView(users_button_);
1358 if (ShouldShowGoIncognito()) {
1359 layout->StartRow(1, 0);
1360 layout->AddView(new views::Separator(views::Separator::HORIZONTAL));
1362 go_incognito_button_ = new BackgroundColorHoverButton(
1363 this,
1364 l10n_util::GetStringUTF16(IDS_PROFILES_GO_INCOGNITO_BUTTON),
1365 *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_INCOGNITO));
1366 layout->StartRow(1, 0);
1367 layout->AddView(go_incognito_button_);
1370 if (display_lock) {
1371 layout->StartRow(1, 0);
1372 layout->AddView(new views::Separator(views::Separator::HORIZONTAL));
1374 lock_button_ = new BackgroundColorHoverButton(
1375 this,
1376 l10n_util::GetStringUTF16(IDS_PROFILES_PROFILE_SIGNOUT_BUTTON),
1377 *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_LOCK));
1378 layout->StartRow(1, 0);
1379 layout->AddView(lock_button_);
1381 return view;
1384 views::View* ProfileChooserView::CreateSupervisedUserDisclaimerView() {
1385 views::View* view = new views::View();
1386 views::GridLayout* layout = CreateSingleColumnLayout(
1387 view, kFixedMenuWidth - 2 * views::kButtonHEdgeMarginNew);
1388 layout->SetInsets(views::kRelatedControlVerticalSpacing,
1389 views::kButtonHEdgeMarginNew,
1390 views::kRelatedControlVerticalSpacing,
1391 views::kButtonHEdgeMarginNew);
1392 views::Label* disclaimer = new views::Label(
1393 avatar_menu_->GetSupervisedUserInformation());
1394 disclaimer->SetMultiLine(true);
1395 disclaimer->SetAllowCharacterBreak(true);
1396 disclaimer->SetHorizontalAlignment(gfx::ALIGN_LEFT);
1397 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
1398 disclaimer->SetFontList(rb->GetFontList(ui::ResourceBundle::SmallFont));
1399 layout->StartRow(1, 0);
1400 layout->AddView(disclaimer);
1402 return view;
1405 views::View* ProfileChooserView::CreateCurrentProfileAccountsView(
1406 const AvatarMenu::Item& avatar_item) {
1407 DCHECK(avatar_item.signed_in);
1408 views::View* view = new views::View();
1409 view->set_background(views::Background::CreateSolidBackground(
1410 profiles::kAvatarBubbleAccountsBackgroundColor));
1411 views::GridLayout* layout = CreateSingleColumnLayout(view, kFixedMenuWidth);
1413 Profile* profile = browser_->profile();
1414 std::string primary_account =
1415 SigninManagerFactory::GetForProfile(profile)->GetAuthenticatedAccountId();
1416 DCHECK(!primary_account.empty());
1417 std::vector<std::string>accounts =
1418 profiles::GetSecondaryAccountsForProfile(profile, primary_account);
1420 // Get state of authentication error, if any.
1421 std::string error_account_id = GetAuthErrorAccountId(profile);
1423 // The primary account should always be listed first.
1424 // TODO(rogerta): we still need to further differentiate the primary account
1425 // from the others in the UI, so more work is likely required here:
1426 // crbug.com/311124.
1427 CreateAccountButton(layout, primary_account, true,
1428 error_account_id == primary_account, kFixedMenuWidth);
1429 for (size_t i = 0; i < accounts.size(); ++i)
1430 CreateAccountButton(layout, accounts[i], false,
1431 error_account_id == accounts[i], kFixedMenuWidth);
1433 if (!profile->IsSupervised()) {
1434 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
1436 add_account_link_ = CreateLink(l10n_util::GetStringFUTF16(
1437 IDS_PROFILES_PROFILE_ADD_ACCOUNT_BUTTON, avatar_item.name), this);
1438 add_account_link_->SetBorder(views::Border::CreateEmptyBorder(
1439 0, views::kButtonVEdgeMarginNew,
1440 views::kRelatedControlVerticalSpacing, 0));
1441 layout->StartRow(1, 0);
1442 layout->AddView(add_account_link_);
1445 return view;
1448 void ProfileChooserView::CreateAccountButton(views::GridLayout* layout,
1449 const std::string& account_id,
1450 bool is_primary_account,
1451 bool reauth_required,
1452 int width) {
1453 std::string email = signin_ui_util::GetDisplayEmail(browser_->profile(),
1454 account_id);
1455 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
1456 const gfx::ImageSkia* delete_default_image =
1457 rb->GetImageNamed(IDR_CLOSE_1).ToImageSkia();
1458 const int kDeleteButtonWidth = delete_default_image->width();
1459 const gfx::ImageSkia warning_default_image = reauth_required ?
1460 *rb->GetImageNamed(IDR_ICON_PROFILES_ACCOUNT_BUTTON_ERROR).ToImageSkia() :
1461 gfx::ImageSkia();
1462 const int kWarningButtonWidth = reauth_required ?
1463 warning_default_image.width() + views::kRelatedButtonHSpacing : 0;
1464 int available_width = width - 2 * views::kButtonHEdgeMarginNew
1465 - kDeleteButtonWidth - kWarningButtonWidth;
1466 views::LabelButton* email_button = new BackgroundColorHoverButton(
1467 reauth_required ? this : NULL,
1468 base::UTF8ToUTF16(email),
1469 warning_default_image);
1470 email_button->SetElideBehavior(gfx::ELIDE_EMAIL);
1471 email_button->SetMinSize(gfx::Size(0, kButtonHeight));
1472 email_button->SetMaxSize(gfx::Size(available_width, kButtonHeight));
1473 layout->StartRow(1, 0);
1474 layout->AddView(email_button);
1476 if (reauth_required)
1477 reauth_account_button_map_[email_button] = account_id;
1479 // Delete button.
1480 if (!browser_->profile()->IsSupervised()) {
1481 views::ImageButton* delete_button = new views::ImageButton(this);
1482 delete_button->SetImageAlignment(views::ImageButton::ALIGN_RIGHT,
1483 views::ImageButton::ALIGN_MIDDLE);
1484 delete_button->SetImage(views::ImageButton::STATE_NORMAL,
1485 delete_default_image);
1486 delete_button->SetImage(views::ImageButton::STATE_HOVERED,
1487 rb->GetImageSkiaNamed(IDR_CLOSE_1_H));
1488 delete_button->SetImage(views::ImageButton::STATE_PRESSED,
1489 rb->GetImageSkiaNamed(IDR_CLOSE_1_P));
1490 delete_button->SetBounds(
1491 width - views::kButtonHEdgeMarginNew - kDeleteButtonWidth,
1492 0, kDeleteButtonWidth, kButtonHeight);
1494 email_button->set_notify_enter_exit_on_child(true);
1495 email_button->AddChildView(delete_button);
1497 // Save the original email address, as the button text could be elided.
1498 delete_account_button_map_[delete_button] = account_id;
1502 views::View* ProfileChooserView::CreateGaiaSigninView() {
1503 GURL url;
1504 int message_id;
1506 switch (view_mode_) {
1507 case profiles::BUBBLE_VIEW_MODE_GAIA_SIGNIN:
1508 url = signin::GetPromoURL(signin_metrics::SOURCE_AVATAR_BUBBLE_SIGN_IN,
1509 false /* auto_close */,
1510 true /* is_constrained */);
1511 message_id = IDS_PROFILES_GAIA_SIGNIN_TITLE;
1512 break;
1513 case profiles::BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT:
1514 url = signin::GetPromoURL(
1515 signin_metrics::SOURCE_AVATAR_BUBBLE_ADD_ACCOUNT,
1516 false /* auto_close */,
1517 true /* is_constrained */);
1518 message_id = IDS_PROFILES_GAIA_ADD_ACCOUNT_TITLE;
1519 break;
1520 case profiles::BUBBLE_VIEW_MODE_GAIA_REAUTH: {
1521 DCHECK(HasAuthError(browser_->profile()));
1522 url = signin::GetReauthURL(browser_->profile(),
1523 GetAuthErrorAccountId(browser_->profile()));
1524 message_id = IDS_PROFILES_GAIA_REAUTH_TITLE;
1525 break;
1527 default:
1528 NOTREACHED() << "Called with invalid mode=" << view_mode_;
1529 return NULL;
1532 // Adds Gaia signin webview
1533 Profile* profile = browser_->profile();
1534 views::WebView* web_view = new views::WebView(profile);
1535 web_view->LoadInitialURL(url);
1536 web_view->GetWebContents()->SetDelegate(this);
1537 web_view->SetPreferredSize(
1538 gfx::Size(kFixedGaiaViewWidth, kFixedGaiaViewHeight));
1539 content::RenderWidgetHostView* rwhv =
1540 web_view->GetWebContents()->GetRenderWidgetHostView();
1541 if (rwhv)
1542 rwhv->SetBackgroundColor(profiles::kAvatarBubbleGaiaBackgroundColor);
1543 TitleCard* title_card = new TitleCard(l10n_util::GetStringUTF16(message_id),
1544 this,
1545 &gaia_signin_cancel_button_);
1546 return TitleCard::AddPaddedTitleCard(
1547 web_view, title_card, kFixedGaiaViewWidth);
1550 views::View* ProfileChooserView::CreateAccountRemovalView() {
1551 views::View* view = new views::View();
1552 views::GridLayout* layout = CreateSingleColumnLayout(
1553 view, kFixedAccountRemovalViewWidth - 2 * views::kButtonHEdgeMarginNew);
1554 layout->SetInsets(0,
1555 views::kButtonHEdgeMarginNew,
1556 views::kButtonVEdgeMarginNew,
1557 views::kButtonHEdgeMarginNew);
1559 const std::string& primary_account = SigninManagerFactory::GetForProfile(
1560 browser_->profile())->GetAuthenticatedAccountId();
1561 bool is_primary_account = primary_account == account_id_to_remove_;
1563 // Adds main text.
1564 layout->StartRowWithPadding(1, 0, 0, views::kUnrelatedControlVerticalSpacing);
1565 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
1566 const gfx::FontList& small_font_list =
1567 rb->GetFontList(ui::ResourceBundle::SmallFont);
1569 if (is_primary_account) {
1570 std::string email = signin_ui_util::GetDisplayEmail(browser_->profile(),
1571 account_id_to_remove_);
1572 std::vector<size_t> offsets;
1573 const base::string16 settings_text =
1574 l10n_util::GetStringUTF16(IDS_PROFILES_SETTINGS_LINK);
1575 const base::string16 primary_account_removal_text =
1576 l10n_util::GetStringFUTF16(IDS_PROFILES_PRIMARY_ACCOUNT_REMOVAL_TEXT,
1577 base::UTF8ToUTF16(email), settings_text, &offsets);
1578 views::StyledLabel* primary_account_removal_label =
1579 new views::StyledLabel(primary_account_removal_text, this);
1580 primary_account_removal_label->AddStyleRange(
1581 gfx::Range(offsets[1], offsets[1] + settings_text.size()),
1582 views::StyledLabel::RangeStyleInfo::CreateForLink());
1583 primary_account_removal_label->SetBaseFontList(small_font_list);
1584 layout->AddView(primary_account_removal_label);
1585 } else {
1586 views::Label* content_label = new views::Label(
1587 l10n_util::GetStringUTF16(IDS_PROFILES_ACCOUNT_REMOVAL_TEXT));
1588 content_label->SetMultiLine(true);
1589 content_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
1590 content_label->SetFontList(small_font_list);
1591 layout->AddView(content_label);
1594 // Adds button.
1595 if (!is_primary_account) {
1596 remove_account_button_ = new views::BlueButton(
1597 this, l10n_util::GetStringUTF16(IDS_PROFILES_ACCOUNT_REMOVAL_BUTTON));
1598 remove_account_button_->SetHorizontalAlignment(
1599 gfx::ALIGN_CENTER);
1600 layout->StartRowWithPadding(
1601 1, 0, 0, views::kUnrelatedControlVerticalSpacing);
1602 layout->AddView(remove_account_button_);
1603 } else {
1604 layout->AddPaddingRow(0, views::kUnrelatedControlVerticalSpacing);
1607 TitleCard* title_card = new TitleCard(
1608 l10n_util::GetStringUTF16(IDS_PROFILES_ACCOUNT_REMOVAL_TITLE),
1609 this, &account_removal_cancel_button_);
1610 return TitleCard::AddPaddedTitleCard(view, title_card,
1611 kFixedAccountRemovalViewWidth);
1614 views::View* ProfileChooserView::CreateWelcomeUpgradeTutorialView(
1615 const AvatarMenu::Item& avatar_item) {
1616 ProfileMetrics::LogProfileNewAvatarMenuUpgrade(
1617 ProfileMetrics::PROFILE_AVATAR_MENU_UPGRADE_VIEW);
1619 // For local profiles, the "Not you" link doesn't make sense.
1620 base::string16 link_message = avatar_item.signed_in ?
1621 l10n_util::GetStringFUTF16(IDS_PROFILES_NOT_YOU, avatar_item.name) :
1622 base::string16();
1624 return CreateTutorialView(
1625 profiles::TUTORIAL_MODE_WELCOME_UPGRADE,
1626 l10n_util::GetStringUTF16(
1627 IDS_PROFILES_WELCOME_UPGRADE_TUTORIAL_TITLE),
1628 l10n_util::GetStringUTF16(
1629 IDS_PROFILES_WELCOME_UPGRADE_TUTORIAL_CONTENT_TEXT),
1630 link_message,
1631 l10n_util::GetStringUTF16(IDS_PROFILES_TUTORIAL_WHATS_NEW_BUTTON),
1632 true /* stack_button */,
1633 &tutorial_not_you_link_,
1634 &tutorial_see_whats_new_button_,
1635 &tutorial_close_button_);
1638 views::View* ProfileChooserView::CreateSigninConfirmationView() {
1639 ProfileMetrics::LogProfileNewAvatarMenuSignin(
1640 ProfileMetrics::PROFILE_AVATAR_MENU_SIGNIN_VIEW);
1642 return CreateTutorialView(
1643 profiles::TUTORIAL_MODE_CONFIRM_SIGNIN,
1644 l10n_util::GetStringUTF16(IDS_PROFILES_CONFIRM_SIGNIN_TUTORIAL_TITLE),
1645 l10n_util::GetStringUTF16(
1646 IDS_PROFILES_CONFIRM_SIGNIN_TUTORIAL_CONTENT_TEXT),
1647 l10n_util::GetStringUTF16(IDS_PROFILES_SYNC_SETTINGS_LINK),
1648 l10n_util::GetStringUTF16(IDS_PROFILES_TUTORIAL_OK_BUTTON),
1649 false /* stack_button */,
1650 &tutorial_sync_settings_link_,
1651 &tutorial_sync_settings_ok_button_,
1652 NULL /* close_button*/);
1655 views::View* ProfileChooserView::CreateSigninErrorView() {
1656 LoginUIService* login_ui_service =
1657 LoginUIServiceFactory::GetForProfile(browser_->profile());
1658 base::string16 last_login_result(login_ui_service->GetLastLoginResult());
1659 return CreateTutorialView(
1660 profiles::TUTORIAL_MODE_SHOW_ERROR,
1661 l10n_util::GetStringUTF16(IDS_PROFILES_ERROR_TUTORIAL_TITLE),
1662 last_login_result,
1663 l10n_util::GetStringUTF16(IDS_PROFILES_PROFILE_TUTORIAL_LEARN_MORE),
1664 base::string16(),
1665 false /* stack_button */,
1666 &tutorial_learn_more_link_,
1667 NULL,
1668 &tutorial_close_button_);
1671 views::View* ProfileChooserView::CreateRightClickTutorialView() {
1672 return CreateTutorialView(
1673 profiles::TUTORIAL_MODE_RIGHT_CLICK_SWITCHING,
1674 l10n_util::GetStringUTF16(IDS_PROFILES_RIGHT_CLICK_TUTORIAL_TITLE),
1675 l10n_util::GetStringUTF16(IDS_PROFILES_RIGHT_CLICK_TUTORIAL_CONTENT_TEXT),
1676 base::string16(),
1677 l10n_util::GetStringUTF16(IDS_PROFILES_TUTORIAL_OK_BUTTON),
1678 false,
1679 nullptr,
1680 &tutorial_sync_settings_ok_button_,
1681 nullptr);
1684 views::View* ProfileChooserView::CreateSwitchUserView() {
1685 views::View* view = new views::View();
1686 views::GridLayout* layout = CreateSingleColumnLayout(
1687 view, kFixedSwitchUserViewWidth);
1688 views::ColumnSet* columns = layout->AddColumnSet(1);
1689 columns->AddPaddingColumn(0, views::kButtonHEdgeMarginNew);
1690 int label_width =
1691 kFixedSwitchUserViewWidth - 2 * views::kButtonHEdgeMarginNew;
1692 columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 0,
1693 views::GridLayout::FIXED, label_width, label_width);
1694 columns->AddPaddingColumn(0, views::kButtonHEdgeMarginNew);
1696 // Adds main text.
1697 layout->StartRowWithPadding(1, 1, 0, views::kUnrelatedControlVerticalSpacing);
1698 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
1699 const gfx::FontList& small_font_list =
1700 rb->GetFontList(ui::ResourceBundle::SmallFont);
1701 const AvatarMenu::Item& avatar_item =
1702 avatar_menu_->GetItemAt(avatar_menu_->GetActiveProfileIndex());
1703 views::Label* content_label = new views::Label(
1704 l10n_util::GetStringFUTF16(
1705 IDS_PROFILES_NOT_YOU_CONTENT_TEXT, avatar_item.name));
1706 content_label->SetMultiLine(true);
1707 content_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
1708 content_label->SetFontList(small_font_list);
1709 layout->AddView(content_label);
1711 // Adds "Add person" button.
1712 layout->StartRowWithPadding(1, 0, 0, views::kUnrelatedControlVerticalSpacing);
1713 layout->AddView(new views::Separator(views::Separator::HORIZONTAL));
1715 add_person_button_ = new BackgroundColorHoverButton(
1716 this,
1717 l10n_util::GetStringUTF16(IDS_PROFILES_ADD_PERSON_BUTTON),
1718 *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_AVATAR));
1719 layout->StartRow(1, 0);
1720 layout->AddView(add_person_button_);
1722 // Adds "Disconnect your Google Account" button.
1723 layout->StartRow(1, 0);
1724 layout->AddView(new views::Separator(views::Separator::HORIZONTAL));
1726 disconnect_button_ = new BackgroundColorHoverButton(
1727 this,
1728 l10n_util::GetStringUTF16(IDS_PROFILES_DISCONNECT_BUTTON),
1729 *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_DISCONNECT));
1730 layout->StartRow(1, 0);
1731 layout->AddView(disconnect_button_);
1733 TitleCard* title_card = new TitleCard(
1734 l10n_util::GetStringFUTF16(IDS_PROFILES_NOT_YOU, avatar_item.name),
1735 this, &switch_user_cancel_button_);
1736 return TitleCard::AddPaddedTitleCard(view, title_card,
1737 kFixedSwitchUserViewWidth);
1740 bool ProfileChooserView::ShouldShowGoIncognito() const {
1741 bool incognito_available =
1742 IncognitoModePrefs::GetAvailability(browser_->profile()->GetPrefs()) !=
1743 IncognitoModePrefs::DISABLED;
1744 return incognito_available && !browser_->profile()->IsGuestSession();
1747 void ProfileChooserView::PostActionPerformed(
1748 ProfileMetrics::ProfileDesktopMenu action_performed) {
1749 ProfileMetrics::LogProfileDesktopMenu(action_performed, gaia_service_type_);
1750 gaia_service_type_ = signin::GAIA_SERVICE_TYPE_NONE;