[Metrics] Make MetricsStateManager take a callback param to check if UMA is enabled.
[chromium-blink-merge.git] / chrome / browser / ui / views / profiles / profile_chooser_view.cc
blobe6cd72c71fedaf24a1217a8ab332eac62b982225
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/profiles/profile_avatar_icon_util.h"
12 #include "chrome/browser/profiles/profile_info_cache.h"
13 #include "chrome/browser/profiles/profile_manager.h"
14 #include "chrome/browser/profiles/profile_metrics.h"
15 #include "chrome/browser/profiles/profile_window.h"
16 #include "chrome/browser/profiles/profiles_state.h"
17 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
18 #include "chrome/browser/signin/signin_manager_factory.h"
19 #include "chrome/browser/signin/signin_promo.h"
20 #include "chrome/browser/ui/browser.h"
21 #include "chrome/browser/ui/browser_commands.h"
22 #include "chrome/browser/ui/browser_dialogs.h"
23 #include "chrome/browser/ui/chrome_pages.h"
24 #include "chrome/browser/ui/singleton_tabs.h"
25 #include "chrome/browser/ui/views/profiles/user_manager_view.h"
26 #include "chrome/common/pref_names.h"
27 #include "chrome/common/url_constants.h"
28 #include "components/signin/core/browser/mutable_profile_oauth2_token_service.h"
29 #include "components/signin/core/browser/profile_oauth2_token_service.h"
30 #include "components/signin/core/browser/signin_manager.h"
31 #include "components/signin/core/common/profile_management_switches.h"
32 #include "grit/chromium_strings.h"
33 #include "grit/generated_resources.h"
34 #include "grit/theme_resources.h"
35 #include "third_party/skia/include/core/SkColor.h"
36 #include "ui/base/l10n/l10n_util.h"
37 #include "ui/base/resource/resource_bundle.h"
38 #include "ui/gfx/canvas.h"
39 #include "ui/gfx/image/image.h"
40 #include "ui/gfx/image/image_skia.h"
41 #include "ui/gfx/text_elider.h"
42 #include "ui/native_theme/native_theme.h"
43 #include "ui/views/controls/button/blue_button.h"
44 #include "ui/views/controls/button/image_button.h"
45 #include "ui/views/controls/button/label_button.h"
46 #include "ui/views/controls/button/menu_button.h"
47 #include "ui/views/controls/label.h"
48 #include "ui/views/controls/link.h"
49 #include "ui/views/controls/separator.h"
50 #include "ui/views/controls/styled_label.h"
51 #include "ui/views/controls/textfield/textfield.h"
52 #include "ui/views/controls/webview/webview.h"
53 #include "ui/views/layout/grid_layout.h"
54 #include "ui/views/layout/layout_constants.h"
55 #include "ui/views/widget/widget.h"
57 namespace {
59 // Helpers --------------------------------------------------------------------
61 const int kFixedMenuWidth = 250;
62 const int kButtonHeight = 29;
63 const int kProfileAvatarTutorialShowMax = 1;
64 const int kFixedGaiaViewHeight = 400;
65 const int kFixedGaiaViewWidth = 360;
66 const int kFixedAccountRemovalViewWidth = 280;
67 const int kFixedEndPreviewViewWidth = 280;
68 const int kLargeImageSide = 88;
70 // Creates a GridLayout with a single column. This ensures that all the child
71 // views added get auto-expanded to fill the full width of the bubble.
72 views::GridLayout* CreateSingleColumnLayout(views::View* view, int width) {
73 views::GridLayout* layout = new views::GridLayout(view);
74 view->SetLayoutManager(layout);
76 views::ColumnSet* columns = layout->AddColumnSet(0);
77 columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 0,
78 views::GridLayout::FIXED, width, width);
79 return layout;
82 views::Link* CreateLink(const base::string16& link_text,
83 views::LinkListener* listener) {
84 views::Link* link_button = new views::Link(link_text);
85 link_button->SetHorizontalAlignment(gfx::ALIGN_LEFT);
86 link_button->SetUnderline(false);
87 link_button->set_listener(listener);
88 return link_button;
91 gfx::ImageSkia CreateSquarePlaceholderImage(int size) {
92 SkBitmap bitmap;
93 bitmap.setConfig(SkBitmap::kA8_Config, size, size);
94 bitmap.allocPixels();
95 bitmap.eraseARGB(0, 0, 0, 0);
96 return gfx::ImageSkia::CreateFrom1xBitmap(bitmap);
99 // BackgroundColorHoverButton -------------------------------------------------
101 // A custom button that allows for setting a background color when hovered over.
102 class BackgroundColorHoverButton : public views::LabelButton {
103 public:
104 BackgroundColorHoverButton(views::ButtonListener* listener,
105 const base::string16& text,
106 const gfx::ImageSkia& normal_icon,
107 const gfx::ImageSkia& hover_icon);
108 virtual ~BackgroundColorHoverButton();
110 private:
111 // views::LabelButton:
112 virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
114 DISALLOW_COPY_AND_ASSIGN(BackgroundColorHoverButton);
117 BackgroundColorHoverButton::BackgroundColorHoverButton(
118 views::ButtonListener* listener,
119 const base::string16& text,
120 const gfx::ImageSkia& normal_icon,
121 const gfx::ImageSkia& hover_icon)
122 : views::LabelButton(listener, text) {
123 SetBorder(views::Border::CreateEmptyBorder(0, views::kButtonHEdgeMarginNew,
124 0, views::kButtonHEdgeMarginNew));
125 set_min_size(gfx::Size(0, kButtonHeight));
126 SetImage(STATE_NORMAL, normal_icon);
127 SetImage(STATE_HOVERED, hover_icon);
128 SetImage(STATE_PRESSED, hover_icon);
131 BackgroundColorHoverButton::~BackgroundColorHoverButton() {}
133 void BackgroundColorHoverButton::OnPaint(gfx::Canvas* canvas) {
134 if ((state() == STATE_PRESSED) || (state() == STATE_HOVERED) || HasFocus()) {
135 canvas->DrawColor(GetNativeTheme()->GetSystemColor(
136 ui::NativeTheme::kColorId_ButtonHoverBackgroundColor));
138 LabelButton::OnPaint(canvas);
141 } // namespace
144 // EditableProfilePhoto -------------------------------------------------
146 // A custom Image control that shows a "change" button when moused over.
147 class EditableProfilePhoto : public views::ImageView {
148 public:
149 EditableProfilePhoto(views::ButtonListener* listener,
150 const gfx::Image& icon,
151 bool is_editing_allowed,
152 const gfx::Rect& bounds)
153 : views::ImageView(),
154 change_photo_button_(NULL) {
155 gfx::Image image = profiles::GetSizedAvatarIcon(
156 icon, true, kLargeImageSide, kLargeImageSide);
157 SetImage(image.ToImageSkia());
158 SetBoundsRect(bounds);
160 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
161 views::ImageView* frame_overlay = new views::ImageView();
162 frame_overlay->SetImage(rb->GetImageNamed(
163 IDR_ICON_PROFILES_AVATAR_PHOTO_FRAME).ToImageSkia());
164 frame_overlay->SetVerticalAlignment(views::ImageView::CENTER);
165 frame_overlay->SetBoundsRect(bounds);
166 AddChildView(frame_overlay);
168 if (!is_editing_allowed)
169 return;
171 set_notify_enter_exit_on_child(true);
173 // Button overlay that appears when hovering over the image.
174 change_photo_button_ = new views::LabelButton(listener, base::string16());
175 change_photo_button_->SetHorizontalAlignment(gfx::ALIGN_CENTER);
176 change_photo_button_->SetBorder(views::Border::NullBorder());
178 const SkColor kBackgroundColor = SkColorSetARGB(65, 255, 255, 255);
179 change_photo_button_->set_background(
180 views::Background::CreateSolidBackground(kBackgroundColor));
181 change_photo_button_->SetImage(views::LabelButton::STATE_NORMAL,
182 *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_EDIT_CAMERA));
184 change_photo_button_->SetBoundsRect(bounds);
185 change_photo_button_->SetVisible(false);
186 AddChildView(change_photo_button_);
189 views::LabelButton* change_photo_button() { return change_photo_button_; }
191 private:
192 // views::View:
193 virtual void OnMouseEntered(const ui::MouseEvent& event) OVERRIDE {
194 if (change_photo_button_)
195 change_photo_button_->SetVisible(true);
198 virtual void OnMouseExited(const ui::MouseEvent& event) OVERRIDE {
199 if (change_photo_button_)
200 change_photo_button_->SetVisible(false);
203 // Button that is shown when hovering over the image view. Can be NULL if
204 // the photo isn't allowed to be edited (e.g. for guest profiles).
205 views::LabelButton* change_photo_button_;
207 DISALLOW_COPY_AND_ASSIGN(EditableProfilePhoto);
211 // EditableProfileName -------------------------------------------------
213 // A custom text control that turns into a textfield for editing when clicked.
214 class EditableProfileName : public views::LabelButton,
215 public views::ButtonListener {
216 public:
217 EditableProfileName(views::TextfieldController* controller,
218 const base::string16& text,
219 bool is_editing_allowed)
220 : views::LabelButton(this, text),
221 profile_name_textfield_(NULL) {
222 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
223 const gfx::FontList& medium_font_list =
224 rb->GetFontList(ui::ResourceBundle::MediumFont);
225 SetFontList(medium_font_list);
226 SetHorizontalAlignment(gfx::ALIGN_CENTER);
228 if (!is_editing_allowed)
229 return;
231 // Show an "edit" pencil icon when hovering over. In the default state,
232 // we need to create an empty placeholder of the correct size, so that
233 // the text doesn't jump around when the hovered icon appears.
234 gfx::ImageSkia hover_image =
235 *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_EDIT_HOVER);
236 SetImage(STATE_NORMAL, CreateSquarePlaceholderImage(hover_image.width()));
237 SetImage(STATE_HOVERED, hover_image);
238 SetImage(STATE_PRESSED,
239 *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_EDIT_PRESSED));
240 // To center the text, we need to offest it by the width of the icon we
241 // are adding. We need to also add a small top/bottom padding to account
242 // for the textfield's border.
243 SetBorder(views::Border::CreateEmptyBorder(2, hover_image.width(), 2, 0));
245 // Textfield that overlaps the button.
246 profile_name_textfield_ = new views::Textfield();
247 profile_name_textfield_->set_controller(controller);
248 profile_name_textfield_->SetFontList(medium_font_list);
249 profile_name_textfield_->SetHorizontalAlignment(gfx::ALIGN_CENTER);
251 profile_name_textfield_->SetVisible(false);
252 AddChildView(profile_name_textfield_);
255 views::Textfield* profile_name_textfield() {
256 return profile_name_textfield_;
259 // Hide the editable textfield to show the profile name button instead.
260 void ShowReadOnlyView() {
261 if (profile_name_textfield_)
262 profile_name_textfield_->SetVisible(false);
265 private:
266 // views::ButtonListener:
267 virtual void ButtonPressed(views::Button* sender,
268 const ui::Event& event) OVERRIDE {
269 if (profile_name_textfield_) {
270 profile_name_textfield_->SetVisible(true);
271 profile_name_textfield_->SetText(GetText());
272 profile_name_textfield_->SelectAll(false);
273 profile_name_textfield_->RequestFocus();
277 // views::LabelButton:
278 virtual bool OnKeyReleased(const ui::KeyEvent& event) OVERRIDE {
279 // Override CustomButton's implementation, which presses the button when
280 // you press space and clicks it when you release space, as the space can be
281 // part of the new profile name typed in the textfield.
282 return false;
285 virtual void Layout() OVERRIDE {
286 if (profile_name_textfield_)
287 profile_name_textfield_->SetBounds(0, 0, width(), height());
288 // This layout trick keeps the text left-aligned and the icon right-aligned.
289 SetHorizontalAlignment(gfx::ALIGN_RIGHT);
290 views::LabelButton::Layout();
291 label()->SetHorizontalAlignment(gfx::ALIGN_CENTER);
294 // Textfield that is shown when editing the profile name. Can be NULL if
295 // the profile name isn't allowed to be edited (e.g. for guest profiles).
296 views::Textfield* profile_name_textfield_;
298 DISALLOW_COPY_AND_ASSIGN(EditableProfileName);
301 // A title card with one back button right aligned and one label center aligned.
302 class TitleCard : public views::View {
303 public:
304 TitleCard(int message_id, views::ButtonListener* listener,
305 views::ImageButton** back_button) {
306 back_button_ = new views::ImageButton(listener);
307 back_button_->SetImageAlignment(views::ImageButton::ALIGN_LEFT,
308 views::ImageButton::ALIGN_MIDDLE);
309 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
310 back_button_->SetImage(views::ImageButton::STATE_NORMAL,
311 rb->GetImageSkiaNamed(IDR_BACK));
312 back_button_->SetImage(views::ImageButton::STATE_HOVERED,
313 rb->GetImageSkiaNamed(IDR_BACK_H));
314 back_button_->SetImage(views::ImageButton::STATE_PRESSED,
315 rb->GetImageSkiaNamed(IDR_BACK_P));
316 back_button_->SetImage(views::ImageButton::STATE_DISABLED,
317 rb->GetImageSkiaNamed(IDR_BACK_D));
318 *back_button = back_button_;
320 title_label_ = new views::Label(l10n_util::GetStringUTF16(message_id));
321 title_label_->SetHorizontalAlignment(gfx::ALIGN_CENTER);
322 const gfx::FontList& medium_font_list =
323 rb->GetFontList(ui::ResourceBundle::MediumFont);
324 title_label_->SetFontList(medium_font_list);
326 AddChildView(back_button_);
327 AddChildView(title_label_);
330 // Creates a new view that has the |title_card| with padding at the top, an
331 // edge-to-edge separator below, and the specified |view| at the bottom.
332 static views::View* AddPaddedTitleCard(views::View* view,
333 TitleCard* title_card,
334 int width) {
335 views::View* titled_view = new views::View();
336 views::GridLayout* layout = new views::GridLayout(titled_view);
337 titled_view->SetLayoutManager(layout);
339 // Column set 0 is a single column layout with horizontal padding at left
340 // and right, and column set 1 is a single column layout with no padding.
341 views::ColumnSet* columns = layout->AddColumnSet(0);
342 columns->AddPaddingColumn(1, views::kButtonHEdgeMarginNew);
343 int available_width = width - 2 * views::kButtonHEdgeMarginNew;
344 columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 0,
345 views::GridLayout::FIXED, available_width, available_width);
346 columns->AddPaddingColumn(1, views::kButtonHEdgeMarginNew);
347 layout->AddColumnSet(1)->AddColumn(views::GridLayout::FILL,
348 views::GridLayout::FILL, 0,views::GridLayout::FIXED, width, width);
350 layout->StartRowWithPadding(1, 0, 0, views::kButtonVEdgeMarginNew);
351 layout->AddView(title_card);
352 layout->StartRowWithPadding(1, 1, 0, views::kRelatedControlVerticalSpacing);
353 layout->AddView(new views::Separator(views::Separator::HORIZONTAL));
355 layout->StartRow(1, 1);
356 layout->AddView(view);
358 return titled_view;
361 private:
362 virtual void Layout() OVERRIDE{
363 back_button_->SetBounds(
364 0, 0, back_button_->GetPreferredSize().width(), height());
365 title_label_->SetBoundsRect(GetContentsBounds());
368 virtual gfx::Size GetPreferredSize() const OVERRIDE{
369 int height = std::max(title_label_->GetPreferredSize().height(),
370 back_button_->GetPreferredSize().height());
371 return gfx::Size(width(), height);
374 views::ImageButton* back_button_;
375 views::Label* title_label_;
377 DISALLOW_COPY_AND_ASSIGN(TitleCard);
380 // ProfileChooserView ---------------------------------------------------------
382 // static
383 ProfileChooserView* ProfileChooserView::profile_bubble_ = NULL;
384 bool ProfileChooserView::close_on_deactivate_for_testing_ = true;
386 // static
387 void ProfileChooserView::ShowBubble(
388 BubbleViewMode view_mode,
389 views::View* anchor_view,
390 views::BubbleBorder::Arrow arrow,
391 views::BubbleBorder::BubbleAlignment border_alignment,
392 const gfx::Rect& anchor_rect,
393 Browser* browser) {
394 if (IsShowing())
395 return;
397 profile_bubble_ = new ProfileChooserView(anchor_view, arrow, anchor_rect,
398 browser, view_mode);
399 views::BubbleDelegateView::CreateBubble(profile_bubble_);
400 profile_bubble_->set_close_on_deactivate(close_on_deactivate_for_testing_);
401 profile_bubble_->SetAlignment(border_alignment);
402 profile_bubble_->GetWidget()->Show();
403 profile_bubble_->SetArrowPaintType(views::BubbleBorder::PAINT_NONE);
406 // static
407 bool ProfileChooserView::IsShowing() {
408 return profile_bubble_ != NULL;
411 // static
412 void ProfileChooserView::Hide() {
413 if (IsShowing())
414 profile_bubble_->GetWidget()->Close();
417 ProfileChooserView::ProfileChooserView(views::View* anchor_view,
418 views::BubbleBorder::Arrow arrow,
419 const gfx::Rect& anchor_rect,
420 Browser* browser,
421 BubbleViewMode view_mode)
422 : BubbleDelegateView(anchor_view, arrow),
423 browser_(browser),
424 view_mode_(view_mode),
425 tutorial_mode_(TUTORIAL_MODE_NONE) {
426 // Reset the default margins inherited from the BubbleDelegateView.
427 set_margins(gfx::Insets());
429 ResetView();
431 avatar_menu_.reset(new AvatarMenu(
432 &g_browser_process->profile_manager()->GetProfileInfoCache(),
433 this,
434 browser_));
435 avatar_menu_->RebuildMenu();
437 ProfileOAuth2TokenService* oauth2_token_service =
438 ProfileOAuth2TokenServiceFactory::GetForProfile(browser_->profile());
439 if (oauth2_token_service)
440 oauth2_token_service->AddObserver(this);
443 ProfileChooserView::~ProfileChooserView() {
444 ProfileOAuth2TokenService* oauth2_token_service =
445 ProfileOAuth2TokenServiceFactory::GetForProfile(browser_->profile());
446 if (oauth2_token_service)
447 oauth2_token_service->RemoveObserver(this);
450 void ProfileChooserView::ResetView() {
451 question_mark_button_ = NULL;
452 manage_accounts_link_ = NULL;
453 signin_current_profile_link_ = NULL;
454 users_button_ = NULL;
455 lock_button_ = NULL;
456 add_account_link_ = NULL;
457 current_profile_photo_ = NULL;
458 current_profile_name_ = NULL;
459 tutorial_ok_button_ = NULL;
460 tutorial_learn_more_link_ = NULL;
461 tutorial_enable_new_profile_management_button_ = NULL;
462 tutorial_end_preview_link_ = NULL;
463 tutorial_send_feedback_button_ = NULL;
464 end_preview_and_relaunch_button_ = NULL;
465 end_preview_cancel_button_ = NULL;
466 remove_account_button_ = NULL;
467 account_removal_cancel_button_ = NULL;
468 gaia_signin_cancel_button_ = NULL;
469 open_other_profile_indexes_map_.clear();
470 current_profile_accounts_map_.clear();
471 tutorial_mode_ = TUTORIAL_MODE_NONE;
474 void ProfileChooserView::Init() {
475 ShowView(view_mode_, avatar_menu_.get());
478 void ProfileChooserView::OnAvatarMenuChanged(
479 AvatarMenu* avatar_menu) {
480 // Refresh the view with the new menu. We can't just update the local copy
481 // as this may have been triggered by a sign out action, in which case
482 // the view is being destroyed.
483 ShowView(BUBBLE_VIEW_MODE_PROFILE_CHOOSER, avatar_menu);
486 void ProfileChooserView::OnRefreshTokenAvailable(
487 const std::string& account_id) {
488 // Refresh the account management view when a new account is added to the
489 // profile.
490 if (view_mode_ == BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT ||
491 view_mode_ == BUBBLE_VIEW_MODE_GAIA_SIGNIN ||
492 view_mode_ == BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT) {
493 ShowView(BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT, avatar_menu_.get());
497 void ProfileChooserView::OnRefreshTokenRevoked(const std::string& account_id) {
498 // Refresh the account management view when an account is removed from the
499 // profile.
500 if (view_mode_ == BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT)
501 ShowView(BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT, avatar_menu_.get());
504 void ProfileChooserView::ShowView(BubbleViewMode view_to_display,
505 AvatarMenu* avatar_menu) {
506 // The account management view should only be displayed if the active profile
507 // is signed in.
508 if (view_to_display == BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT) {
509 const AvatarMenu::Item& active_item = avatar_menu->GetItemAt(
510 avatar_menu->GetActiveProfileIndex());
511 DCHECK(active_item.signed_in);
514 // Records the last tutorial mode.
515 TutorialMode last_tutorial_mode = tutorial_mode_;
516 ResetView();
517 RemoveAllChildViews(true);
518 view_mode_ = view_to_display;
520 views::GridLayout* layout;
521 views::View* sub_view;
522 switch (view_mode_) {
523 case BUBBLE_VIEW_MODE_GAIA_SIGNIN:
524 case BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT:
525 layout = CreateSingleColumnLayout(this, kFixedGaiaViewWidth);
526 sub_view = CreateGaiaSigninView(
527 view_mode_ == BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT);
528 break;
529 case BUBBLE_VIEW_MODE_ACCOUNT_REMOVAL:
530 layout = CreateSingleColumnLayout(this, kFixedAccountRemovalViewWidth);
531 sub_view = CreateAccountRemovalView();
532 break;
533 case BUBBLE_VIEW_MODE_END_PREVIEW:
534 layout = CreateSingleColumnLayout(this, kFixedEndPreviewViewWidth);
535 sub_view = CreateEndPreviewView();
536 break;
537 default:
538 layout = CreateSingleColumnLayout(this, kFixedMenuWidth);
539 sub_view = CreateProfileChooserView(avatar_menu, last_tutorial_mode);
541 sub_view->set_background(views::Background::CreateSolidBackground(
542 GetNativeTheme()->GetSystemColor(
543 ui::NativeTheme::kColorId_DialogBackground)));
545 layout->StartRow(1, 0);
546 layout->AddView(sub_view);
547 Layout();
548 if (GetBubbleFrameView())
549 SizeToContents();
552 void ProfileChooserView::WindowClosing() {
553 DCHECK_EQ(profile_bubble_, this);
554 profile_bubble_ = NULL;
557 void ProfileChooserView::ButtonPressed(views::Button* sender,
558 const ui::Event& event) {
559 // Disable button after clicking so that it doesn't get clicked twice and
560 // start a second action... which can crash Chrome. But don't disable if it
561 // has no parent (like in tests) because that will also crash.
562 if (sender->parent())
563 sender->SetEnabled(false);
565 if (sender == users_button_) {
566 profiles::ShowUserManagerMaybeWithTutorial(browser_->profile());
567 // If this is a guest session, also close all the guest browser windows.
568 if (browser_->profile()->IsGuestSession())
569 profiles::CloseGuestProfileWindows();
570 } else if (sender == lock_button_) {
571 profiles::LockProfile(browser_->profile());
572 } else if (sender == tutorial_ok_button_) {
573 // If the user manually dismissed the tutorial, never show it again by
574 // setting the number of times shown to the maximum plus 1, so that later we
575 // could distinguish between the dismiss case and the case when the tutorial
576 // is indeed shown for the maximum number of times.
577 browser_->profile()->GetPrefs()->SetInteger(
578 prefs::kProfileAvatarTutorialShown, kProfileAvatarTutorialShowMax + 1);
580 ProfileMetrics::LogProfileUpgradeEnrollment(
581 ProfileMetrics::PROFILE_ENROLLMENT_CLOSE_WELCOME_CARD);
582 ShowView(BUBBLE_VIEW_MODE_PROFILE_CHOOSER, avatar_menu_.get());
583 } else if (sender == tutorial_enable_new_profile_management_button_) {
584 ProfileMetrics::LogProfileUpgradeEnrollment(
585 ProfileMetrics::PROFILE_ENROLLMENT_ACCEPT_NEW_PROFILE_MGMT);
586 profiles::EnableNewProfileManagementPreview();
587 } else if (sender == remove_account_button_) {
588 RemoveAccount();
589 } else if (sender == account_removal_cancel_button_) {
590 account_id_to_remove_.clear();
591 ShowView(BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT, avatar_menu_.get());
592 } else if (sender == gaia_signin_cancel_button_) {
593 std::string primary_account =
594 SigninManagerFactory::GetForProfile(browser_->profile())->
595 GetAuthenticatedUsername();
596 ShowView(primary_account.empty() ? BUBBLE_VIEW_MODE_PROFILE_CHOOSER :
597 BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT,
598 avatar_menu_.get());
599 } else if (sender == question_mark_button_) {
600 tutorial_mode_ = TUTORIAL_MODE_SEND_FEEDBACK;
601 ShowView(BUBBLE_VIEW_MODE_PROFILE_CHOOSER, avatar_menu_.get());
602 } else if (sender == tutorial_send_feedback_button_) {
603 ProfileMetrics::LogProfileUpgradeEnrollment(
604 ProfileMetrics::PROFILE_ENROLLMENT_SEND_FEEDBACK);
605 chrome::OpenFeedbackDialog(browser_);
606 } else if (sender == end_preview_and_relaunch_button_) {
607 ProfileMetrics::LogProfileUpgradeEnrollment(
608 ProfileMetrics::PROFILE_ENROLLMENT_DISABLE_NEW_PROFILE_MGMT);
609 profiles::DisableNewProfileManagementPreview();
610 } else if (sender == end_preview_cancel_button_) {
611 tutorial_mode_ = TUTORIAL_MODE_SEND_FEEDBACK;
612 ShowView(BUBBLE_VIEW_MODE_PROFILE_CHOOSER, avatar_menu_.get());
613 } else if (current_profile_photo_ &&
614 sender == current_profile_photo_->change_photo_button()) {
615 avatar_menu_->EditProfile(avatar_menu_->GetActiveProfileIndex());
616 } else if (sender == signin_current_profile_link_) {
617 // Only show the inline signin if the new UI flag is flipped. Otherwise,
618 // use the tab signin page.
619 if (switches::IsNewProfileManagement())
620 ShowView(BUBBLE_VIEW_MODE_GAIA_SIGNIN, avatar_menu_.get());
621 else
622 chrome::ShowBrowserSignin(browser_, signin::SOURCE_MENU);
623 } else {
624 // Either one of the "other profiles", or one of the profile accounts
625 // buttons was pressed.
626 ButtonIndexes::const_iterator profile_match =
627 open_other_profile_indexes_map_.find(sender);
628 if (profile_match != open_other_profile_indexes_map_.end()) {
629 avatar_menu_->SwitchToProfile(
630 profile_match->second,
631 ui::DispositionFromEventFlags(event.flags()) == NEW_WINDOW,
632 ProfileMetrics::SWITCH_PROFILE_ICON);
633 } else {
634 // This was a profile accounts button.
635 AccountButtonIndexes::const_iterator account_match =
636 current_profile_accounts_map_.find(sender);
637 DCHECK(account_match != current_profile_accounts_map_.end());
638 account_id_to_remove_ = account_match->second;
639 ShowView(BUBBLE_VIEW_MODE_ACCOUNT_REMOVAL, avatar_menu_.get());
644 void ProfileChooserView::RemoveAccount() {
645 DCHECK(!account_id_to_remove_.empty());
646 MutableProfileOAuth2TokenService* oauth2_token_service =
647 ProfileOAuth2TokenServiceFactory::GetPlatformSpecificForProfile(
648 browser_->profile());
649 if (oauth2_token_service)
650 oauth2_token_service->RevokeCredentials(account_id_to_remove_);
651 account_id_to_remove_.clear();
653 ShowView(BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT, avatar_menu_.get());
656 void ProfileChooserView::LinkClicked(views::Link* sender, int event_flags) {
657 if (sender == manage_accounts_link_) {
658 // This link can either mean show/hide the account management view,
659 // depending on which view it is displayed. ShowView() will DCHECK if
660 // the account management view is displayed for non signed-in users.
661 ShowView(
662 view_mode_ == BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT ?
663 BUBBLE_VIEW_MODE_PROFILE_CHOOSER :
664 BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT,
665 avatar_menu_.get());
666 } else if (sender == add_account_link_) {
667 ShowView(BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT, avatar_menu_.get());
668 } else if (sender == tutorial_learn_more_link_) {
669 ProfileMetrics::LogProfileUpgradeEnrollment(
670 ProfileMetrics::PROFILE_ENROLLMENT_LAUNCH_LEARN_MORE);
671 // TODO(guohui): update |learn_more_url| once it is decided.
672 const GURL lear_more_url("https://support.google.com/chrome/?hl=en#to");
673 chrome::NavigateParams params(
674 browser_->profile(),
675 lear_more_url,
676 content::PAGE_TRANSITION_LINK);
677 params.disposition = NEW_FOREGROUND_TAB;
678 chrome::Navigate(&params);
679 } else {
680 DCHECK(sender == tutorial_end_preview_link_);
681 ShowView(BUBBLE_VIEW_MODE_END_PREVIEW, avatar_menu_.get());
685 void ProfileChooserView::StyledLabelLinkClicked(
686 const gfx::Range& range, int event_flags) {
687 chrome::ShowSettings(browser_);
690 bool ProfileChooserView::HandleKeyEvent(views::Textfield* sender,
691 const ui::KeyEvent& key_event) {
692 views::Textfield* name_textfield =
693 current_profile_name_->profile_name_textfield();
694 DCHECK(sender == name_textfield);
696 if (key_event.key_code() == ui::VKEY_RETURN ||
697 key_event.key_code() == ui::VKEY_TAB) {
698 // Pressing Tab/Enter commits the new profile name, unless it's empty.
699 base::string16 new_profile_name = name_textfield->text();
700 if (new_profile_name.empty())
701 return true;
703 const AvatarMenu::Item& active_item = avatar_menu_->GetItemAt(
704 avatar_menu_->GetActiveProfileIndex());
705 Profile* profile = g_browser_process->profile_manager()->GetProfile(
706 active_item.profile_path);
707 DCHECK(profile);
709 if (profile->IsManaged())
710 return true;
712 profiles::UpdateProfileName(profile, new_profile_name);
713 current_profile_name_->ShowReadOnlyView();
714 return true;
716 return false;
719 views::View* ProfileChooserView::CreateProfileChooserView(
720 AvatarMenu* avatar_menu,
721 TutorialMode last_tutorial_mode) {
722 // TODO(guohui, noms): the view should be customized based on whether new
723 // profile management preview is enabled or not.
725 views::View* view = new views::View();
726 views::GridLayout* layout = CreateSingleColumnLayout(view, kFixedMenuWidth);
727 // Separate items into active and alternatives.
728 Indexes other_profiles;
729 views::View* tutorial_view = NULL;
730 views::View* current_profile_view = NULL;
731 views::View* current_profile_accounts = NULL;
732 views::View* option_buttons_view = NULL;
733 bool is_new_profile_management = switches::IsNewProfileManagement();
734 for (size_t i = 0; i < avatar_menu->GetNumberOfItems(); ++i) {
735 const AvatarMenu::Item& item = avatar_menu->GetItemAt(i);
736 if (item.active) {
737 option_buttons_view = CreateOptionsView(item.signed_in);
738 current_profile_view = CreateCurrentProfileView(item, false);
739 if (view_mode_ == BUBBLE_VIEW_MODE_PROFILE_CHOOSER) {
740 if (is_new_profile_management) {
741 tutorial_view = last_tutorial_mode == TUTORIAL_MODE_SEND_FEEDBACK ?
742 CreateSendPreviewFeedbackView() :
743 CreatePreviewEnabledTutorialView(
744 item, last_tutorial_mode == TUTORIAL_MODE_PREVIEW_ENABLED);
745 } else {
746 tutorial_view = CreateNewProfileManagementPreviewView();
748 } else {
749 current_profile_accounts = CreateCurrentProfileAccountsView(item);
751 } else {
752 other_profiles.push_back(i);
756 if (tutorial_view) {
757 // Be sure not to track the tutorial display on View refresh, and only count
758 // the preview-promo view, shown when New Profile Management is off.
759 if (tutorial_mode_ != last_tutorial_mode && !is_new_profile_management) {
760 ProfileMetrics::LogProfileUpgradeEnrollment(
761 ProfileMetrics::PROFILE_ENROLLMENT_SHOW_PREVIEW_PROMO);
763 layout->StartRow(1, 0);
764 layout->AddView(tutorial_view);
767 if (!current_profile_view) {
768 // Guest windows don't have an active profile.
769 current_profile_view = CreateGuestProfileView();
770 option_buttons_view = CreateOptionsView(false);
773 layout->StartRow(1, 0);
774 layout->AddView(current_profile_view);
776 if (view_mode_ == BUBBLE_VIEW_MODE_PROFILE_CHOOSER) {
777 layout->StartRow(1, 0);
778 if (switches::IsFastUserSwitching())
779 layout->AddView(CreateOtherProfilesView(other_profiles));
780 } else {
781 DCHECK(current_profile_accounts);
782 layout->StartRow(0, 0);
783 layout->AddView(new views::Separator(views::Separator::HORIZONTAL));
784 layout->StartRow(1, 0);
785 layout->AddView(current_profile_accounts);
788 layout->StartRow(0, 0);
789 layout->AddView(new views::Separator(views::Separator::HORIZONTAL));
791 // Option buttons. Only available with the new profile management flag.
792 if (option_buttons_view) {
793 layout->StartRow(0, 0);
794 layout->AddView(option_buttons_view);
797 return view;
800 views::View* ProfileChooserView::CreatePreviewEnabledTutorialView(
801 const AvatarMenu::Item& current_avatar_item,
802 bool tutorial_shown) {
803 if (!switches::IsNewProfileManagementPreviewEnabled())
804 return NULL;
806 Profile* profile = browser_->profile();
807 const int show_count = profile->GetPrefs()->GetInteger(
808 prefs::kProfileAvatarTutorialShown);
809 // Do not show the tutorial if user has dismissed it.
810 if (show_count > kProfileAvatarTutorialShowMax)
811 return NULL;
813 if (!tutorial_shown) {
814 if (show_count == kProfileAvatarTutorialShowMax)
815 return NULL;
816 profile->GetPrefs()->SetInteger(
817 prefs::kProfileAvatarTutorialShown, show_count + 1);
820 return CreateTutorialView(
821 TUTORIAL_MODE_PREVIEW_ENABLED,
822 l10n_util::GetStringUTF16(IDS_PROFILES_PREVIEW_ENABLED_TUTORIAL_TITLE),
823 l10n_util::GetStringUTF16(
824 IDS_PROFILES_PREVIEW_ENABLED_TUTORIAL_CONTENT_TEXT),
825 l10n_util::GetStringUTF16(IDS_PROFILES_PROFILE_TUTORIAL_LEARN_MORE),
826 l10n_util::GetStringUTF16(IDS_PROFILES_TUTORIAL_OK_BUTTON),
827 &tutorial_learn_more_link_,
828 &tutorial_ok_button_);
831 views::View* ProfileChooserView::CreateSendPreviewFeedbackView() {
832 return CreateTutorialView(
833 TUTORIAL_MODE_SEND_FEEDBACK,
834 l10n_util::GetStringUTF16(IDS_PROFILES_FEEDBACK_TUTORIAL_TITLE),
835 l10n_util::GetStringUTF16(
836 IDS_PROFILES_FEEDBACK_TUTORIAL_CONTENT_TEXT),
837 l10n_util::GetStringUTF16(IDS_PROFILES_END_PREVIEW),
838 l10n_util::GetStringUTF16(IDS_PROFILES_SEND_FEEDBACK_BUTTON),
839 &tutorial_end_preview_link_,
840 &tutorial_send_feedback_button_);
843 views::View* ProfileChooserView::CreateTutorialView(
844 TutorialMode tutorial_mode,
845 const base::string16& title_text,
846 const base::string16& content_text,
847 const base::string16& link_text,
848 const base::string16& button_text,
849 views::Link** link,
850 views::LabelButton** button) {
851 tutorial_mode_ = tutorial_mode;
853 views::View* view = new views::View();
854 view->set_background(views::Background::CreateSolidBackground(
855 profiles::kAvatarTutorialBackgroundColor));
856 views::GridLayout* layout = CreateSingleColumnLayout(view,
857 kFixedMenuWidth - 2 * views::kButtonHEdgeMarginNew);
858 layout->SetInsets(views::kButtonVEdgeMarginNew,
859 views::kButtonHEdgeMarginNew,
860 views::kButtonVEdgeMarginNew,
861 views::kButtonHEdgeMarginNew);
863 // Adds title.
864 views::Label* title_label = new views::Label(title_text);
865 title_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
866 title_label->SetAutoColorReadabilityEnabled(false);
867 title_label->SetEnabledColor(SK_ColorWHITE);
868 title_label->SetFontList(ui::ResourceBundle::GetSharedInstance().GetFontList(
869 ui::ResourceBundle::MediumFont));
870 layout->StartRow(1, 0);
871 layout->AddView(title_label);
873 // Adds body content.
874 views::Label* content_label = new views::Label(content_text);
875 content_label->SetMultiLine(true);
876 content_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
877 content_label->SetAutoColorReadabilityEnabled(false);
878 content_label->SetEnabledColor(profiles::kAvatarTutorialContentTextColor);
879 layout->StartRowWithPadding(1, 0, 0, views::kRelatedControlVerticalSpacing);
880 layout->AddView(content_label);
882 // Adds links and buttons.
883 views::View* button_row = new views::View();
884 views::GridLayout* button_layout = new views::GridLayout(button_row);
885 views::ColumnSet* button_columns = button_layout->AddColumnSet(0);
886 button_columns->AddColumn(views::GridLayout::LEADING,
887 views::GridLayout::CENTER, 0, views::GridLayout::USE_PREF, 0, 0);
888 button_columns->AddPaddingColumn(
889 1, views::kUnrelatedControlHorizontalSpacing);
890 button_columns->AddColumn(views::GridLayout::TRAILING,
891 views::GridLayout::CENTER, 0, views::GridLayout::USE_PREF, 0, 0);
892 button_row->SetLayoutManager(button_layout);
894 *link = CreateLink(link_text, this);
895 (*link)->SetHorizontalAlignment(gfx::ALIGN_LEFT);
896 (*link)->SetAutoColorReadabilityEnabled(false);
897 (*link)->SetEnabledColor(SK_ColorWHITE);
898 button_layout->StartRow(1, 0);
899 button_layout->AddView(*link);
901 *button = new views::LabelButton(this, button_text);
902 (*button)->SetHorizontalAlignment(gfx::ALIGN_CENTER);
903 (*button)->SetStyle(views::Button::STYLE_BUTTON);
904 button_layout->AddView(*button);
906 layout->StartRowWithPadding(1, 0, 0, views::kUnrelatedControlVerticalSpacing);
907 layout->AddView(button_row);
909 // Adds a padded caret image at the bottom.
910 views::View* padded_caret_view = new views::View();
911 views::GridLayout* padded_caret_layout =
912 new views::GridLayout(padded_caret_view);
913 views::ColumnSet* padded_columns = padded_caret_layout->AddColumnSet(0);
914 padded_columns->AddPaddingColumn(0, views::kButtonHEdgeMarginNew);
915 padded_columns->AddColumn(views::GridLayout::LEADING,
916 views::GridLayout::CENTER, 0, views::GridLayout::USE_PREF, 0, 0);
917 padded_caret_view->SetLayoutManager(padded_caret_layout);
919 views::ImageView* caret_image_view = new views::ImageView();
920 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
921 caret_image_view->SetImage(
922 *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_CARET));
924 padded_caret_layout->StartRow(1, 0);
925 padded_caret_layout->AddView(caret_image_view);
927 views::View* view_with_caret = new views::View();
928 views::GridLayout* layout_with_caret =
929 CreateSingleColumnLayout(view_with_caret, kFixedMenuWidth);
930 layout_with_caret->StartRow(1, 0);
931 layout_with_caret->AddView(view);
932 layout_with_caret->StartRow(1, 0);
933 layout_with_caret->AddView(padded_caret_view);
934 return view_with_caret;
937 views::View* ProfileChooserView::CreateCurrentProfileView(
938 const AvatarMenu::Item& avatar_item,
939 bool is_guest) {
940 views::View* view = new views::View();
941 int column_width = kFixedMenuWidth - 2 * views::kButtonHEdgeMarginNew;
942 views::GridLayout* layout = CreateSingleColumnLayout(view, column_width);
943 layout->SetInsets(views::kButtonVEdgeMarginNew,
944 views::kButtonHEdgeMarginNew,
945 views::kUnrelatedControlVerticalSpacing,
946 views::kButtonHEdgeMarginNew);
948 // Profile icon, centered.
949 float x_offset = (column_width - kLargeImageSide) / 2;
950 current_profile_photo_ = new EditableProfilePhoto(
951 this, avatar_item.icon, !is_guest,
952 gfx::Rect(x_offset, 0, kLargeImageSide, kLargeImageSide));
954 if (switches::IsNewProfileManagementPreviewEnabled()) {
955 question_mark_button_ = new views::ImageButton(this);
956 question_mark_button_->SetImageAlignment(
957 views::ImageButton::ALIGN_LEFT, views::ImageButton::ALIGN_MIDDLE);
958 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
959 question_mark_button_->SetImage(views::ImageButton::STATE_NORMAL,
960 rb->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_QUESTION_STABLE));
961 question_mark_button_->SetImage(views::ImageButton::STATE_HOVERED,
962 rb->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_QUESTION_HOVER));
963 question_mark_button_->SetImage(views::ImageButton::STATE_PRESSED,
964 rb->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_QUESTION_SELECT));
965 gfx::Size preferred_size = question_mark_button_->GetPreferredSize();
966 question_mark_button_->SetBounds(
967 0, 0, preferred_size.width(), preferred_size.height());
968 current_profile_photo_->AddChildView(question_mark_button_);
971 layout->StartRow(1, 0);
972 layout->AddView(current_profile_photo_);
974 // Profile name, centered.
975 current_profile_name_ = new EditableProfileName(
976 this, profiles::GetAvatarNameForProfile(browser_->profile()), !is_guest);
977 layout->StartRow(1, 0);
978 layout->AddView(current_profile_name_);
980 if (is_guest)
981 return view;
983 // The available links depend on the type of profile that is active.
984 layout->StartRow(1, 0);
985 if (avatar_item.signed_in) {
986 if (switches::IsNewProfileManagement()) {
987 base::string16 link_title = l10n_util::GetStringUTF16(
988 view_mode_ == BUBBLE_VIEW_MODE_PROFILE_CHOOSER ?
989 IDS_PROFILES_PROFILE_MANAGE_ACCOUNTS_BUTTON :
990 IDS_PROFILES_PROFILE_HIDE_MANAGE_ACCOUNTS_BUTTON);
991 manage_accounts_link_ = CreateLink(link_title, this);
992 manage_accounts_link_->SetHorizontalAlignment(gfx::ALIGN_CENTER);
993 layout->AddView(manage_accounts_link_);
994 } else {
995 views::Label* email_label = new views::Label(avatar_item.sync_state);
996 email_label->SetHorizontalAlignment(gfx::ALIGN_CENTER);
997 layout->AddView(email_label);
999 } else {
1000 signin_current_profile_link_ = new views::BlueButton(
1001 this, l10n_util::GetStringFUTF16(IDS_SYNC_START_SYNC_BUTTON_LABEL,
1002 l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME)));
1003 layout->AddView(signin_current_profile_link_);
1006 return view;
1009 views::View* ProfileChooserView::CreateGuestProfileView() {
1010 gfx::Image guest_icon =
1011 ui::ResourceBundle::GetSharedInstance().GetImageNamed(
1012 profiles::GetPlaceholderAvatarIconResourceID());
1013 AvatarMenu::Item guest_avatar_item(0, 0, guest_icon);
1014 guest_avatar_item.active = true;
1015 guest_avatar_item.name = l10n_util::GetStringUTF16(
1016 IDS_PROFILES_GUEST_PROFILE_NAME);
1017 guest_avatar_item.signed_in = false;
1019 return CreateCurrentProfileView(guest_avatar_item, true);
1022 views::View* ProfileChooserView::CreateOtherProfilesView(
1023 const Indexes& avatars_to_show) {
1024 views::View* view = new views::View();
1025 views::GridLayout* layout = CreateSingleColumnLayout(view, kFixedMenuWidth);
1027 int num_avatars_to_show = avatars_to_show.size();
1028 for (int i = 0; i < num_avatars_to_show; ++i) {
1029 const size_t index = avatars_to_show[i];
1030 const AvatarMenu::Item& item = avatar_menu_->GetItemAt(index);
1031 const int kSmallImageSide = 32;
1033 gfx::Image image = profiles::GetSizedAvatarIcon(
1034 item.icon, true, kSmallImageSide, kSmallImageSide);
1036 views::LabelButton* button = new BackgroundColorHoverButton(
1037 this,
1038 item.name,
1039 *image.ToImageSkia(),
1040 *image.ToImageSkia());
1041 button->set_min_size(gfx::Size(
1042 0, kButtonHeight + views::kRelatedControlVerticalSpacing));
1044 open_other_profile_indexes_map_[button] = index;
1046 layout->StartRow(1, 0);
1047 layout->AddView(new views::Separator(views::Separator::HORIZONTAL));
1048 layout->StartRow(1, 0);
1049 layout->AddView(button);
1052 return view;
1055 views::View* ProfileChooserView::CreateOptionsView(bool enable_lock) {
1056 if (!switches::IsNewProfileManagement())
1057 return NULL;
1059 views::View* view = new views::View();
1060 views::GridLayout* layout;
1062 // Only signed-in users have the ability to lock.
1063 if (enable_lock) {
1064 layout = new views::GridLayout(view);
1065 views::ColumnSet* columns = layout->AddColumnSet(0);
1066 int width_of_lock_button =
1067 2 * views::kUnrelatedControlLargeHorizontalSpacing + 12;
1068 int width_of_users_button = kFixedMenuWidth - width_of_lock_button;
1069 columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 0,
1070 views::GridLayout::FIXED, width_of_users_button,
1071 width_of_users_button);
1072 columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 0,
1073 views::GridLayout::FIXED, width_of_lock_button,
1074 width_of_lock_button);
1075 view->SetLayoutManager(layout);
1076 } else {
1077 layout = CreateSingleColumnLayout(view, kFixedMenuWidth);
1080 base::string16 text = browser_->profile()->IsGuestSession() ?
1081 l10n_util::GetStringUTF16(IDS_PROFILES_EXIT_GUEST) :
1082 l10n_util::GetStringFUTF16(IDS_PROFILES_NOT_YOU_BUTTON,
1083 profiles::GetAvatarNameForProfile(browser_->profile()));
1084 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
1085 users_button_ = new BackgroundColorHoverButton(
1086 this,
1087 text,
1088 *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_AVATAR),
1089 *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_AVATAR));
1090 users_button_->set_min_size(gfx::Size(
1091 0, kButtonHeight + views::kRelatedControlVerticalSpacing));
1093 layout->StartRow(1, 0);
1094 layout->AddView(users_button_);
1096 if (enable_lock) {
1097 lock_button_ = new BackgroundColorHoverButton(
1098 this,
1099 base::string16(),
1100 *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_LOCK),
1101 *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_LOCK));
1102 lock_button_->set_min_size(gfx::Size(
1103 0, kButtonHeight + views::kRelatedControlVerticalSpacing));
1104 layout->AddView(lock_button_);
1106 return view;
1109 views::View* ProfileChooserView::CreateCurrentProfileAccountsView(
1110 const AvatarMenu::Item& avatar_item) {
1111 DCHECK(avatar_item.signed_in);
1112 views::View* view = new views::View();
1113 view->set_background(views::Background::CreateSolidBackground(
1114 profiles::kAvatarBubbleAccountsBackgroundColor));
1115 views::GridLayout* layout = CreateSingleColumnLayout(view, kFixedMenuWidth);
1117 Profile* profile = browser_->profile();
1118 std::string primary_account =
1119 SigninManagerFactory::GetForProfile(profile)->GetAuthenticatedUsername();
1120 DCHECK(!primary_account.empty());
1121 std::vector<std::string>accounts =
1122 profiles::GetSecondaryAccountsForProfile(profile, primary_account);
1124 // The primary account should always be listed first.
1125 // TODO(rogerta): we still need to further differentiate the primary account
1126 // from the others in the UI, so more work is likely required here:
1127 // crbug.com/311124.
1128 CreateAccountButton(layout, primary_account, true, kFixedMenuWidth);
1129 for (size_t i = 0; i < accounts.size(); ++i)
1130 CreateAccountButton(layout, accounts[i], false, kFixedMenuWidth);
1131 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
1133 add_account_link_ = CreateLink(l10n_util::GetStringFUTF16(
1134 IDS_PROFILES_PROFILE_ADD_ACCOUNT_BUTTON, avatar_item.name), this);
1135 add_account_link_->SetBorder(views::Border::CreateEmptyBorder(
1136 0, views::kButtonVEdgeMarginNew,
1137 views::kRelatedControlVerticalSpacing, 0));
1138 layout->StartRow(1, 0);
1139 layout->AddView(add_account_link_);
1140 return view;
1143 void ProfileChooserView::CreateAccountButton(views::GridLayout* layout,
1144 const std::string& account,
1145 bool is_primary_account,
1146 int width) {
1147 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
1148 const gfx::ImageSkia* default_image =
1149 rb->GetImageNamed(IDR_CLOSE_1).ToImageSkia();
1150 int kDeleteButtonWidth = default_image->width();
1151 int available_width = width -
1152 kDeleteButtonWidth - views::kButtonHEdgeMarginNew;
1154 views::LabelButton* email_button = new BackgroundColorHoverButton(
1155 NULL,
1156 gfx::ElideEmail(base::UTF8ToUTF16(account),
1157 rb->GetFontList(ui::ResourceBundle::BaseFont),
1158 available_width),
1159 gfx::ImageSkia(),
1160 gfx::ImageSkia());
1161 layout->StartRow(1, 0);
1162 layout->AddView(email_button);
1164 // Delete button.
1165 views::ImageButton* delete_button = new views::ImageButton(this);
1166 delete_button->SetImageAlignment(views::ImageButton::ALIGN_RIGHT,
1167 views::ImageButton::ALIGN_MIDDLE);
1168 delete_button->SetImage(views::ImageButton::STATE_NORMAL,
1169 default_image);
1170 delete_button->SetImage(views::ImageButton::STATE_HOVERED,
1171 rb->GetImageSkiaNamed(IDR_CLOSE_1_H));
1172 delete_button->SetImage(views::ImageButton::STATE_PRESSED,
1173 rb->GetImageSkiaNamed(IDR_CLOSE_1_P));
1174 delete_button->SetBounds(
1175 available_width, 0, kDeleteButtonWidth, kButtonHeight);
1177 email_button->set_notify_enter_exit_on_child(true);
1178 email_button->AddChildView(delete_button);
1180 // Save the original email address, as the button text could be elided.
1181 current_profile_accounts_map_[delete_button] = account;
1184 views::View* ProfileChooserView::CreateGaiaSigninView(
1185 bool add_secondary_account) {
1186 // Adds Gaia signin webview
1187 Profile* profile = browser_->profile();
1188 views::WebView* web_view = new views::WebView(profile);
1189 signin::Source source = add_secondary_account ?
1190 signin::SOURCE_AVATAR_BUBBLE_ADD_ACCOUNT :
1191 signin::SOURCE_AVATAR_BUBBLE_SIGN_IN;
1192 GURL url(signin::GetPromoURL(
1193 source, false /* auto_close */, true /* is_constrained */));
1194 web_view->LoadInitialURL(url);
1195 web_view->SetPreferredSize(
1196 gfx::Size(kFixedGaiaViewWidth, kFixedGaiaViewHeight));
1198 TitleCard* title_card = new TitleCard(
1199 add_secondary_account ? IDS_PROFILES_GAIA_ADD_ACCOUNT_TITLE :
1200 IDS_PROFILES_GAIA_SIGNIN_TITLE,
1201 this, &gaia_signin_cancel_button_);
1202 return TitleCard::AddPaddedTitleCard(
1203 web_view, title_card, kFixedGaiaViewWidth);
1206 views::View* ProfileChooserView::CreateAccountRemovalView() {
1207 views::View* view = new views::View();
1208 views::GridLayout* layout = CreateSingleColumnLayout(
1209 view, kFixedAccountRemovalViewWidth - 2 * views::kButtonHEdgeMarginNew);
1210 layout->SetInsets(0,
1211 views::kButtonHEdgeMarginNew,
1212 views::kButtonVEdgeMarginNew,
1213 views::kButtonHEdgeMarginNew);
1215 const std::string& primary_account = SigninManagerFactory::GetForProfile(
1216 browser_->profile())->GetAuthenticatedUsername();
1217 bool is_primary_account = primary_account == account_id_to_remove_;
1219 // Adds main text.
1220 layout->StartRowWithPadding(1, 0, 0, views::kUnrelatedControlVerticalSpacing);
1221 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
1222 const gfx::FontList& small_font_list =
1223 rb->GetFontList(ui::ResourceBundle::SmallFont);
1225 if (is_primary_account) {
1226 std::vector<size_t> offsets;
1227 const base::string16 settings_text =
1228 l10n_util::GetStringUTF16(IDS_PROFILES_SETTINGS_LINK);
1229 const base::string16 primary_account_removal_text =
1230 l10n_util::GetStringFUTF16(IDS_PROFILES_PRIMARY_ACCOUNT_REMOVAL_TEXT,
1231 base::UTF8ToUTF16(account_id_to_remove_), settings_text, &offsets);
1232 views::StyledLabel* primary_account_removal_label =
1233 new views::StyledLabel(primary_account_removal_text, this);
1234 primary_account_removal_label->AddStyleRange(
1235 gfx::Range(offsets[1], offsets[1] + settings_text.size()),
1236 views::StyledLabel::RangeStyleInfo::CreateForLink());
1237 primary_account_removal_label->SetBaseFontList(small_font_list);
1238 layout->AddView(primary_account_removal_label);
1239 } else {
1240 views::Label* content_label = new views::Label(
1241 l10n_util::GetStringUTF16(IDS_PROFILES_ACCOUNT_REMOVAL_TEXT));
1242 content_label->SetMultiLine(true);
1243 content_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
1244 content_label->SetFontList(small_font_list);
1245 layout->AddView(content_label);
1248 // Adds button.
1249 if (!is_primary_account) {
1250 remove_account_button_ = new views::BlueButton(
1251 this, l10n_util::GetStringUTF16(IDS_PROFILES_ACCOUNT_REMOVAL_BUTTON));
1252 remove_account_button_->SetHorizontalAlignment(
1253 gfx::ALIGN_CENTER);
1254 layout->StartRowWithPadding(
1255 1, 0, 0, views::kUnrelatedControlVerticalSpacing);
1256 layout->AddView(remove_account_button_);
1257 } else {
1258 layout->AddPaddingRow(0, views::kUnrelatedControlVerticalSpacing);
1261 TitleCard* title_card = new TitleCard(IDS_PROFILES_ACCOUNT_REMOVAL_TITLE,
1262 this, &account_removal_cancel_button_);
1263 return TitleCard::AddPaddedTitleCard(view, title_card,
1264 kFixedAccountRemovalViewWidth);
1267 views::View* ProfileChooserView::CreateNewProfileManagementPreviewView() {
1268 return CreateTutorialView(
1269 TUTORIAL_MODE_ENABLE_PREVIEW,
1270 l10n_util::GetStringUTF16(IDS_PROFILES_PREVIEW_TUTORIAL_TITLE),
1271 l10n_util::GetStringUTF16(IDS_PROFILES_PREVIEW_TUTORIAL_CONTENT_TEXT),
1272 l10n_util::GetStringUTF16(IDS_PROFILES_PROFILE_TUTORIAL_LEARN_MORE),
1273 l10n_util::GetStringUTF16(IDS_PROFILES_TUTORIAL_TRY_BUTTON),
1274 &tutorial_learn_more_link_,
1275 &tutorial_enable_new_profile_management_button_);
1278 views::View* ProfileChooserView::CreateEndPreviewView() {
1279 views::View* view = new views::View();
1280 views::GridLayout* layout = CreateSingleColumnLayout(
1281 view, kFixedAccountRemovalViewWidth - 2 * views::kButtonHEdgeMarginNew);
1282 layout->SetInsets(0,
1283 views::kButtonHEdgeMarginNew,
1284 views::kButtonVEdgeMarginNew,
1285 views::kButtonHEdgeMarginNew);
1287 // Adds main text.
1288 views::Label* content_label = new views::Label(
1289 l10n_util::GetStringUTF16(IDS_PROFILES_END_PREVIEW_TEXT));
1290 content_label->SetMultiLine(true);
1291 content_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
1292 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
1293 const gfx::FontList& small_font_list =
1294 rb->GetFontList(ui::ResourceBundle::SmallFont);
1295 content_label->SetFontList(small_font_list);
1296 layout->StartRowWithPadding(1, 0, 0, views::kUnrelatedControlVerticalSpacing);
1297 layout->AddView(content_label);
1299 // Adds button.
1300 end_preview_and_relaunch_button_ = new views::BlueButton(
1301 this, l10n_util::GetStringUTF16(IDS_PROFILES_END_PREVIEW_AND_RELAUNCH));
1302 end_preview_and_relaunch_button_->SetHorizontalAlignment(
1303 gfx::ALIGN_CENTER);
1304 layout->StartRowWithPadding(
1305 1, 0, 0, views::kUnrelatedControlVerticalSpacing);
1306 layout->AddView(end_preview_and_relaunch_button_);
1308 TitleCard* title_card = new TitleCard(
1309 IDS_PROFILES_END_PREVIEW, this, &end_preview_cancel_button_);
1310 return TitleCard::AddPaddedTitleCard(
1311 view, title_card, kFixedAccountRemovalViewWidth);