profile_chooser_view.cc revision 03b57e008b61dfcb1fbad3aea950ae0e001748b0
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. 4 5#include "chrome/browser/ui/views/profiles/profile_chooser_view.h" 6 7#include "base/prefs/pref_service.h" 8#include "base/strings/utf_string_conversions.h" 9#include "chrome/browser/browser_process.h" 10#include "chrome/browser/lifetime/application_lifetime.h" 11#include "chrome/browser/prefs/incognito_mode_prefs.h" 12#include "chrome/browser/profiles/profile_avatar_icon_util.h" 13#include "chrome/browser/profiles/profile_info_cache.h" 14#include "chrome/browser/profiles/profile_manager.h" 15#include "chrome/browser/profiles/profile_metrics.h" 16#include "chrome/browser/profiles/profile_window.h" 17#include "chrome/browser/profiles/profiles_state.h" 18#include "chrome/browser/signin/profile_oauth2_token_service_factory.h" 19#include "chrome/browser/signin/signin_header_helper.h" 20#include "chrome/browser/signin/signin_manager_factory.h" 21#include "chrome/browser/signin/signin_promo.h" 22#include "chrome/browser/signin/signin_ui_util.h" 23#include "chrome/browser/ui/browser.h" 24#include "chrome/browser/ui/browser_commands.h" 25#include "chrome/browser/ui/browser_dialogs.h" 26#include "chrome/browser/ui/chrome_pages.h" 27#include "chrome/browser/ui/singleton_tabs.h" 28#include "chrome/browser/ui/views/profiles/user_manager_view.h" 29#include "chrome/browser/ui/webui/signin/login_ui_service.h" 30#include "chrome/browser/ui/webui/signin/login_ui_service_factory.h" 31#include "chrome/common/pref_names.h" 32#include "chrome/common/url_constants.h" 33#include "components/signin/core/browser/mutable_profile_oauth2_token_service.h" 34#include "components/signin/core/browser/profile_oauth2_token_service.h" 35#include "components/signin/core/browser/signin_error_controller.h" 36#include "components/signin/core/browser/signin_manager.h" 37#include "components/signin/core/common/profile_management_switches.h" 38#include "grit/chromium_strings.h" 39#include "grit/generated_resources.h" 40#include "grit/theme_resources.h" 41#include "third_party/skia/include/core/SkColor.h" 42#include "ui/base/l10n/l10n_util.h" 43#include "ui/base/resource/resource_bundle.h" 44#include "ui/gfx/canvas.h" 45#include "ui/gfx/image/image.h" 46#include "ui/gfx/image/image_skia.h" 47#include "ui/gfx/path.h" 48#include "ui/gfx/skia_util.h" 49#include "ui/gfx/text_elider.h" 50#include "ui/native_theme/native_theme.h" 51#include "ui/views/controls/button/blue_button.h" 52#include "ui/views/controls/button/image_button.h" 53#include "ui/views/controls/button/label_button.h" 54#include "ui/views/controls/button/menu_button.h" 55#include "ui/views/controls/label.h" 56#include "ui/views/controls/link.h" 57#include "ui/views/controls/separator.h" 58#include "ui/views/controls/styled_label.h" 59#include "ui/views/controls/textfield/textfield.h" 60#include "ui/views/controls/webview/webview.h" 61#include "ui/views/layout/grid_layout.h" 62#include "ui/views/layout/layout_constants.h" 63#include "ui/views/widget/widget.h" 64 65namespace { 66 67// Helpers -------------------------------------------------------------------- 68 69const int kFixedMenuWidth = 250; 70const int kButtonHeight = 32; 71const int kFixedGaiaViewHeight = 440; 72const int kFixedGaiaViewWidth = 360; 73const int kFixedAccountRemovalViewWidth = 280; 74const int kFixedSwitchUserViewWidth = 280; 75const int kLargeImageSide = 88; 76 77// Creates a GridLayout with a single column. This ensures that all the child 78// views added get auto-expanded to fill the full width of the bubble. 79views::GridLayout* CreateSingleColumnLayout(views::View* view, int width) { 80 views::GridLayout* layout = new views::GridLayout(view); 81 view->SetLayoutManager(layout); 82 83 views::ColumnSet* columns = layout->AddColumnSet(0); 84 columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 0, 85 views::GridLayout::FIXED, width, width); 86 return layout; 87} 88 89views::Link* CreateLink(const base::string16& link_text, 90 views::LinkListener* listener) { 91 views::Link* link_button = new views::Link(link_text); 92 link_button->SetHorizontalAlignment(gfx::ALIGN_LEFT); 93 link_button->SetUnderline(false); 94 link_button->set_listener(listener); 95 return link_button; 96} 97 98gfx::ImageSkia CreateSquarePlaceholderImage(int size) { 99 SkBitmap bitmap; 100 bitmap.allocPixels(SkImageInfo::MakeA8(size, size)); 101 bitmap.eraseARGB(0, 0, 0, 0); 102 return gfx::ImageSkia::CreateFrom1xBitmap(bitmap); 103} 104 105bool HasAuthError(Profile* profile) { 106 const SigninErrorController* error = 107 profiles::GetSigninErrorController(profile); 108 return error && error->HasError(); 109} 110 111std::string GetAuthErrorAccountId(Profile* profile) { 112 const SigninErrorController* error = 113 profiles::GetSigninErrorController(profile); 114 if (!error) 115 return std::string(); 116 117 return error->error_account_id(); 118} 119 120std::string GetAuthErrorUsername(Profile* profile) { 121 const SigninErrorController* error = 122 profiles::GetSigninErrorController(profile); 123 if (!error) 124 return std::string(); 125 126 return error->error_username(); 127} 128 129// BackgroundColorHoverButton ------------------------------------------------- 130 131// A custom button that allows for setting a background color when hovered over. 132class BackgroundColorHoverButton : public views::LabelButton { 133 public: 134 BackgroundColorHoverButton(views::ButtonListener* listener, 135 const base::string16& text, 136 const gfx::ImageSkia& icon) 137 : views::LabelButton(listener, text) { 138 SetImageLabelSpacing(views::kItemLabelSpacing); 139 SetBorder(views::Border::CreateEmptyBorder( 140 0, views::kButtonHEdgeMarginNew, 0, views::kButtonHEdgeMarginNew)); 141 SetMinSize(gfx::Size(0, 142 kButtonHeight + views::kRelatedControlVerticalSpacing)); 143 SetImage(STATE_NORMAL, icon); 144 SetFocusable(true); 145 } 146 147 virtual ~BackgroundColorHoverButton() {} 148 149 private: 150 // views::LabelButton: 151 virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE { 152 if ((state() == STATE_PRESSED) || 153 (state() == STATE_HOVERED) || 154 HasFocus()) { 155 canvas->DrawColor(GetNativeTheme()->GetSystemColor( 156 ui::NativeTheme::kColorId_ButtonHoverBackgroundColor)); 157 } 158 LabelButton::OnPaint(canvas); 159 } 160 161 DISALLOW_COPY_AND_ASSIGN(BackgroundColorHoverButton); 162}; 163 164// SizedContainer ------------------------------------------------- 165 166// A simple container view that takes an explicit preferred size. 167class SizedContainer : public views::View { 168 public: 169 explicit SizedContainer(const gfx::Size& preferred_size) 170 : preferred_size_(preferred_size) {} 171 172 virtual gfx::Size GetPreferredSize() const OVERRIDE { 173 return preferred_size_; 174 } 175 176 private: 177 gfx::Size preferred_size_; 178}; 179 180} // namespace 181 182// RightAlignedIconLabelButton ------------------------------------------------- 183 184// A custom LabelButton that has a centered text and right aligned icon. 185class RightAlignedIconLabelButton : public views::LabelButton { 186 public: 187 RightAlignedIconLabelButton(views::ButtonListener* listener, 188 const base::string16& text) 189 : views::LabelButton(listener, text) { 190 } 191 192 protected: 193 virtual 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); 198 } 199 200 DISALLOW_COPY_AND_ASSIGN(RightAlignedIconLabelButton); 201}; 202 203// EditableProfilePhoto ------------------------------------------------- 204 205// A custom Image control that shows a "change" button when moused over. 206class EditableProfilePhoto : public views::LabelButton { 207 public: 208 EditableProfilePhoto(views::ButtonListener* listener, 209 const gfx::Image& icon, 210 bool is_editing_allowed, 211 const gfx::Rect& bounds) 212 : views::LabelButton(listener, base::string16()), 213 photo_overlay_(NULL) { 214 gfx::Image image = profiles::GetSizedAvatarIcon( 215 icon, true, kLargeImageSide, kLargeImageSide); 216 SetImage(views::LabelButton::STATE_NORMAL, *image.ToImageSkia()); 217 SetBorder(views::Border::NullBorder()); 218 SetBoundsRect(bounds); 219 220 // Calculate the circular mask that will be used to display the photo. 221 circular_mask_.addCircle(SkIntToScalar(bounds.width() / 2), 222 SkIntToScalar(bounds.height() / 2), 223 SkIntToScalar(bounds.width() / 2)); 224 225 if (!is_editing_allowed) { 226 SetEnabled(false); 227 return; 228 } 229 230 SetFocusable(true); 231 set_notify_enter_exit_on_child(true); 232 233 // Photo overlay that appears when hovering over the button. 234 photo_overlay_ = new views::ImageView(); 235 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)); 241 242 photo_overlay_->SetSize(bounds.size()); 243 photo_overlay_->SetVisible(false); 244 AddChildView(photo_overlay_); 245 } 246 247 virtual 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); 251 } 252 253 virtual void PaintChildren(gfx::Canvas* canvas, 254 const views::CullSet& cull_set) OVERRIDE { 255 // Display any children (the "change photo" overlay) as a circle. 256 canvas->ClipPath(circular_mask_, true); 257 View::PaintChildren(canvas, cull_set); 258 } 259 260 private: 261 // views::CustomButton: 262 virtual 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); 267 } 268 269 virtual void OnFocus() OVERRIDE { 270 views::LabelButton::OnFocus(); 271 if (photo_overlay_) 272 photo_overlay_->SetVisible(true); 273 } 274 275 virtual 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); 280 } 281 282 gfx::Path circular_mask_; 283 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_; 287 288 DISALLOW_COPY_AND_ASSIGN(EditableProfilePhoto); 289}; 290 291// EditableProfileName ------------------------------------------------- 292 293// A custom text control that turns into a textfield for editing when clicked. 294class 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); 307 308 if (!is_editing_allowed) { 309 SetBorder(views::Border::CreateEmptyBorder(2, 0, 2, 0)); 310 return; 311 } 312 313 SetFocusable(true); 314 // Show an "edit" pencil icon when hovering over. In the default state, 315 // we need to create an empty placeholder of the correct size, so that 316 // the text doesn't jump around when the hovered icon appears. 317 gfx::ImageSkia hover_image = 318 *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_EDIT_HOVER); 319 SetImage(STATE_NORMAL, CreateSquarePlaceholderImage(hover_image.width())); 320 SetImage(STATE_HOVERED, hover_image); 321 SetImage(STATE_PRESSED, 322 *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_EDIT_PRESSED)); 323 // To center the text, we need to offest it by the width of the icon we 324 // are adding and its padding. We need to also add a small top/bottom 325 // padding to account for the textfield's border. 326 const int kIconTextLabelButtonSpacing = 5; 327 SetBorder(views::Border::CreateEmptyBorder( 328 2, hover_image.width() + kIconTextLabelButtonSpacing, 2, 0)); 329 330 // Textfield that overlaps the button. 331 profile_name_textfield_ = new views::Textfield(); 332 profile_name_textfield_->set_controller(controller); 333 profile_name_textfield_->SetFontList(medium_font_list); 334 profile_name_textfield_->SetHorizontalAlignment(gfx::ALIGN_CENTER); 335 336 profile_name_textfield_->SetVisible(false); 337 AddChildView(profile_name_textfield_); 338 } 339 340 views::Textfield* profile_name_textfield() { 341 return profile_name_textfield_; 342 } 343 344 // Hide the editable textfield to show the profile name button instead. 345 void ShowReadOnlyView() { 346 if (profile_name_textfield_) 347 profile_name_textfield_->SetVisible(false); 348 } 349 350 private: 351 // views::ButtonListener: 352 virtual void ButtonPressed(views::Button* sender, 353 const ui::Event& event) OVERRIDE { 354 if (profile_name_textfield_) { 355 profile_name_textfield_->SetVisible(true); 356 profile_name_textfield_->SetText(GetText()); 357 profile_name_textfield_->SelectAll(false); 358 profile_name_textfield_->RequestFocus(); 359 } 360 } 361 362 // views::LabelButton: 363 virtual bool OnKeyReleased(const ui::KeyEvent& event) OVERRIDE { 364 // Override CustomButton's implementation, which presses the button when 365 // you press space and clicks it when you release space, as the space can be 366 // part of the new profile name typed in the textfield. 367 return false; 368 } 369 370 virtual void Layout() OVERRIDE { 371 if (profile_name_textfield_) 372 profile_name_textfield_->SetBounds(0, 0, width(), height()); 373 RightAlignedIconLabelButton::Layout(); 374 } 375 376 virtual void OnFocus() OVERRIDE { 377 RightAlignedIconLabelButton::OnFocus(); 378 SetState(STATE_HOVERED); 379 } 380 381 virtual void OnBlur() OVERRIDE { 382 RightAlignedIconLabelButton::OnBlur(); 383 SetState(STATE_NORMAL); 384 } 385 386 // Textfield that is shown when editing the profile name. Can be NULL if 387 // the profile name isn't allowed to be edited (e.g. for guest profiles). 388 views::Textfield* profile_name_textfield_; 389 390 DISALLOW_COPY_AND_ASSIGN(EditableProfileName); 391}; 392 393// A title card with one back button right aligned and one label center aligned. 394class TitleCard : public views::View { 395 public: 396 TitleCard(const base::string16& message, views::ButtonListener* listener, 397 views::ImageButton** back_button) { 398 back_button_ = new views::ImageButton(listener); 399 back_button_->SetImageAlignment(views::ImageButton::ALIGN_LEFT, 400 views::ImageButton::ALIGN_MIDDLE); 401 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance(); 402 back_button_->SetImage(views::ImageButton::STATE_NORMAL, 403 rb->GetImageSkiaNamed(IDR_BACK)); 404 back_button_->SetImage(views::ImageButton::STATE_HOVERED, 405 rb->GetImageSkiaNamed(IDR_BACK_H)); 406 back_button_->SetImage(views::ImageButton::STATE_PRESSED, 407 rb->GetImageSkiaNamed(IDR_BACK_P)); 408 back_button_->SetImage(views::ImageButton::STATE_DISABLED, 409 rb->GetImageSkiaNamed(IDR_BACK_D)); 410 back_button_->SetFocusable(true); 411 *back_button = back_button_; 412 413 title_label_ = new views::Label(message); 414 title_label_->SetHorizontalAlignment(gfx::ALIGN_CENTER); 415 const gfx::FontList& medium_font_list = 416 rb->GetFontList(ui::ResourceBundle::MediumFont); 417 title_label_->SetFontList(medium_font_list); 418 419 AddChildView(back_button_); 420 AddChildView(title_label_); 421 } 422 423 // Creates a new view that has the |title_card| with padding at the top, an 424 // edge-to-edge separator below, and the specified |view| at the bottom. 425 static views::View* AddPaddedTitleCard(views::View* view, 426 TitleCard* title_card, 427 int width) { 428 views::View* titled_view = new views::View(); 429 views::GridLayout* layout = new views::GridLayout(titled_view); 430 titled_view->SetLayoutManager(layout); 431 432 // Column set 0 is a single column layout with horizontal padding at left 433 // and right, and column set 1 is a single column layout with no padding. 434 views::ColumnSet* columns = layout->AddColumnSet(0); 435 columns->AddPaddingColumn(1, views::kButtonHEdgeMarginNew); 436 int available_width = width - 2 * views::kButtonHEdgeMarginNew; 437 columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 0, 438 views::GridLayout::FIXED, available_width, available_width); 439 columns->AddPaddingColumn(1, views::kButtonHEdgeMarginNew); 440 layout->AddColumnSet(1)->AddColumn(views::GridLayout::FILL, 441 views::GridLayout::FILL, 0,views::GridLayout::FIXED, width, width); 442 443 layout->StartRowWithPadding(1, 0, 0, views::kButtonVEdgeMarginNew); 444 layout->AddView(title_card); 445 layout->StartRowWithPadding(1, 1, 0, views::kRelatedControlVerticalSpacing); 446 layout->AddView(new views::Separator(views::Separator::HORIZONTAL)); 447 448 layout->StartRow(1, 1); 449 layout->AddView(view); 450 451 return titled_view; 452 } 453 454 private: 455 virtual void Layout() OVERRIDE{ 456 int back_button_width = back_button_->GetPreferredSize().width(); 457 back_button_->SetBounds(0, 0, back_button_width, height()); 458 int label_padding = back_button_width + views::kButtonHEdgeMarginNew; 459 int label_width = width() - 2 * label_padding; 460 DCHECK_GT(label_width, 0); 461 title_label_->SetBounds(label_padding, 0, label_width, height()); 462 } 463 464 virtual gfx::Size GetPreferredSize() const OVERRIDE{ 465 int height = std::max(title_label_->GetPreferredSize().height(), 466 back_button_->GetPreferredSize().height()); 467 return gfx::Size(width(), height); 468 } 469 470 views::ImageButton* back_button_; 471 views::Label* title_label_; 472 473 DISALLOW_COPY_AND_ASSIGN(TitleCard); 474}; 475 476// ProfileChooserView --------------------------------------------------------- 477 478// static 479ProfileChooserView* ProfileChooserView::profile_bubble_ = NULL; 480bool ProfileChooserView::close_on_deactivate_for_testing_ = true; 481 482// static 483void ProfileChooserView::ShowBubble( 484 profiles::BubbleViewMode view_mode, 485 profiles::TutorialMode tutorial_mode, 486 const signin::ManageAccountsParams& manage_accounts_params, 487 views::View* anchor_view, 488 views::BubbleBorder::Arrow arrow, 489 views::BubbleBorder::BubbleAlignment border_alignment, 490 Browser* browser) { 491 if (IsShowing()) { 492 if (tutorial_mode != profiles::TUTORIAL_MODE_NONE) { 493 profile_bubble_->tutorial_mode_ = tutorial_mode; 494 profile_bubble_->ShowView(view_mode, profile_bubble_->avatar_menu_.get()); 495 } 496 return; 497 } 498 499 profile_bubble_ = new ProfileChooserView(anchor_view, arrow, browser, 500 view_mode, tutorial_mode, manage_accounts_params.service_type); 501 views::BubbleDelegateView::CreateBubble(profile_bubble_); 502 profile_bubble_->set_close_on_deactivate(close_on_deactivate_for_testing_); 503 profile_bubble_->SetAlignment(border_alignment); 504 profile_bubble_->GetWidget()->Show(); 505 profile_bubble_->SetArrowPaintType(views::BubbleBorder::PAINT_NONE); 506} 507 508// static 509bool ProfileChooserView::IsShowing() { 510 return profile_bubble_ != NULL; 511} 512 513// static 514void ProfileChooserView::Hide() { 515 if (IsShowing()) 516 profile_bubble_->GetWidget()->Close(); 517} 518 519ProfileChooserView::ProfileChooserView(views::View* anchor_view, 520 views::BubbleBorder::Arrow arrow, 521 Browser* browser, 522 profiles::BubbleViewMode view_mode, 523 profiles::TutorialMode tutorial_mode, 524 signin::GAIAServiceType service_type) 525 : BubbleDelegateView(anchor_view, arrow), 526 browser_(browser), 527 view_mode_(view_mode), 528 tutorial_mode_(tutorial_mode), 529 gaia_service_type_(service_type) { 530 // Reset the default margins inherited from the BubbleDelegateView. 531 // Add a small bottom inset so that the bubble's rounded corners show up. 532 set_margins(gfx::Insets(0, 0, 1, 0)); 533 set_background(views::Background::CreateSolidBackground( 534 GetNativeTheme()->GetSystemColor( 535 ui::NativeTheme::kColorId_DialogBackground))); 536 ResetView(); 537 538 avatar_menu_.reset(new AvatarMenu( 539 &g_browser_process->profile_manager()->GetProfileInfoCache(), 540 this, 541 browser_)); 542 avatar_menu_->RebuildMenu(); 543 544 ProfileOAuth2TokenService* oauth2_token_service = 545 ProfileOAuth2TokenServiceFactory::GetForProfile(browser_->profile()); 546 if (oauth2_token_service) 547 oauth2_token_service->AddObserver(this); 548} 549 550ProfileChooserView::~ProfileChooserView() { 551 ProfileOAuth2TokenService* oauth2_token_service = 552 ProfileOAuth2TokenServiceFactory::GetForProfile(browser_->profile()); 553 if (oauth2_token_service) 554 oauth2_token_service->RemoveObserver(this); 555} 556 557void ProfileChooserView::ResetView() { 558 open_other_profile_indexes_map_.clear(); 559 delete_account_button_map_.clear(); 560 reauth_account_button_map_.clear(); 561 manage_accounts_link_ = NULL; 562 signin_current_profile_link_ = NULL; 563 auth_error_email_button_ = NULL; 564 current_profile_photo_ = NULL; 565 current_profile_name_ = NULL; 566 users_button_ = NULL; 567 go_incognito_button_ = NULL; 568 lock_button_ = NULL; 569 add_account_link_ = NULL; 570 gaia_signin_cancel_button_ = NULL; 571 remove_account_button_ = NULL; 572 account_removal_cancel_button_ = NULL; 573 add_person_button_ = NULL; 574 disconnect_button_ = NULL; 575 switch_user_cancel_button_ = NULL; 576 tutorial_sync_settings_ok_button_ = NULL; 577 tutorial_close_button_ = NULL; 578 tutorial_sync_settings_link_ = NULL; 579 tutorial_see_whats_new_button_ = NULL; 580 tutorial_not_you_link_ = NULL; 581 tutorial_learn_more_link_ = NULL; 582} 583 584void ProfileChooserView::Init() { 585 // If view mode is PROFILE_CHOOSER but there is an auth error, force 586 // ACCOUNT_MANAGEMENT mode. 587 if (view_mode_ == profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER && 588 HasAuthError(browser_->profile()) && 589 switches::IsEnableAccountConsistency() && 590 avatar_menu_->GetItemAt(avatar_menu_->GetActiveProfileIndex()). 591 signed_in) { 592 view_mode_ = profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT; 593 } 594 595 ShowView(view_mode_, avatar_menu_.get()); 596} 597 598void ProfileChooserView::OnAvatarMenuChanged( 599 AvatarMenu* avatar_menu) { 600 // Do not refresh the avatar menu if the user is on a signin related view. 601 if (view_mode_ == profiles::BUBBLE_VIEW_MODE_GAIA_SIGNIN || 602 view_mode_ == profiles::BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT || 603 view_mode_ == profiles::BUBBLE_VIEW_MODE_GAIA_REAUTH) { 604 return; 605 } 606 607 // Refresh the view with the new menu. We can't just update the local copy 608 // as this may have been triggered by a sign out action, in which case 609 // the view is being destroyed. 610 ShowView(profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER, avatar_menu); 611} 612 613void ProfileChooserView::OnRefreshTokenAvailable( 614 const std::string& account_id) { 615 if (view_mode_ == profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT || 616 view_mode_ == profiles::BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT || 617 view_mode_ == profiles::BUBBLE_VIEW_MODE_GAIA_REAUTH) { 618 // The account management UI is only available through the 619 // --enable-account-consistency flag. 620 ShowView(switches::IsEnableAccountConsistency() ? 621 profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT : 622 profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER, avatar_menu_.get()); 623 } 624} 625 626void ProfileChooserView::OnRefreshTokenRevoked(const std::string& account_id) { 627 // Refresh the account management view when an account is removed from the 628 // profile. 629 if (view_mode_ == profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT) 630 ShowView(profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT, avatar_menu_.get()); 631} 632 633void ProfileChooserView::ShowView(profiles::BubbleViewMode view_to_display, 634 AvatarMenu* avatar_menu) { 635 // The account management view should only be displayed if the active profile 636 // is signed in. 637 if (view_to_display == profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT) { 638 DCHECK(switches::IsEnableAccountConsistency()); 639 const AvatarMenu::Item& active_item = avatar_menu->GetItemAt( 640 avatar_menu->GetActiveProfileIndex()); 641 DCHECK(active_item.signed_in); 642 } 643 644 if (browser_->profile()->IsSupervised() && 645 (view_to_display == profiles::BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT || 646 view_to_display == profiles::BUBBLE_VIEW_MODE_ACCOUNT_REMOVAL)) { 647 LOG(WARNING) << "Supervised user attempted to add/remove account"; 648 return; 649 } 650 651 ResetView(); 652 RemoveAllChildViews(true); 653 view_mode_ = view_to_display; 654 655 views::GridLayout* layout; 656 views::View* sub_view; 657 switch (view_mode_) { 658 case profiles::BUBBLE_VIEW_MODE_GAIA_SIGNIN: 659 case profiles::BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT: 660 case profiles::BUBBLE_VIEW_MODE_GAIA_REAUTH: 661 layout = CreateSingleColumnLayout(this, kFixedGaiaViewWidth); 662 sub_view = CreateGaiaSigninView(); 663 break; 664 case profiles::BUBBLE_VIEW_MODE_ACCOUNT_REMOVAL: 665 layout = CreateSingleColumnLayout(this, kFixedAccountRemovalViewWidth); 666 sub_view = CreateAccountRemovalView(); 667 break; 668 case profiles::BUBBLE_VIEW_MODE_SWITCH_USER: 669 layout = CreateSingleColumnLayout(this, kFixedSwitchUserViewWidth); 670 sub_view = CreateSwitchUserView(); 671 ProfileMetrics::LogProfileNewAvatarMenuNotYou( 672 ProfileMetrics::PROFILE_AVATAR_MENU_NOT_YOU_VIEW); 673 break; 674 default: 675 layout = CreateSingleColumnLayout(this, kFixedMenuWidth); 676 sub_view = CreateProfileChooserView(avatar_menu); 677 } 678 // Clears tutorial mode for all non-profile-chooser views. 679 if (view_mode_ != profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER) 680 tutorial_mode_ = profiles::TUTORIAL_MODE_NONE; 681 682 layout->StartRow(1, 0); 683 layout->AddView(sub_view); 684 Layout(); 685 if (GetBubbleFrameView()) 686 SizeToContents(); 687} 688 689void ProfileChooserView::WindowClosing() { 690 DCHECK_EQ(profile_bubble_, this); 691 profile_bubble_ = NULL; 692 693 if (tutorial_mode_ == profiles::TUTORIAL_MODE_CONFIRM_SIGNIN) { 694 LoginUIServiceFactory::GetForProfile(browser_->profile())-> 695 SyncConfirmationUIClosed(false /* configure_sync_first */); 696 } 697} 698 699void ProfileChooserView::ButtonPressed(views::Button* sender, 700 const ui::Event& event) { 701 // Disable button after clicking so that it doesn't get clicked twice and 702 // start a second action... which can crash Chrome. But don't disable if it 703 // has no parent (like in tests) because that will also crash. 704 if (sender->parent()) 705 sender->SetEnabled(false); 706 707 if (sender == users_button_) { 708 // If this is a guest session, also close all the guest browser windows. 709 if (browser_->profile()->IsGuestSession()) { 710 chrome::ShowUserManager(base::FilePath()); 711 profiles::CloseGuestProfileWindows(); 712 } else { 713 chrome::ShowUserManager(browser_->profile()->GetPath()); 714 } 715 PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_OPEN_USER_MANAGER); 716 } else if (sender == go_incognito_button_) { 717 DCHECK(ShouldShowGoIncognito()); 718 chrome::NewIncognitoWindow(browser_); 719 } else if (sender == lock_button_) { 720 profiles::LockProfile(browser_->profile()); 721 PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_LOCK); 722 } else if (sender == auth_error_email_button_) { 723 ShowView(profiles::BUBBLE_VIEW_MODE_GAIA_REAUTH, avatar_menu_.get()); 724 } else if (sender == tutorial_sync_settings_ok_button_) { 725 LoginUIServiceFactory::GetForProfile(browser_->profile())-> 726 SyncConfirmationUIClosed(false /* configure_sync_first */); 727 DismissTutorial(); 728 ProfileMetrics::LogProfileNewAvatarMenuSignin( 729 ProfileMetrics::PROFILE_AVATAR_MENU_SIGNIN_OK); 730 } else if (sender == tutorial_close_button_) { 731 DCHECK(tutorial_mode_ != profiles::TUTORIAL_MODE_NONE && 732 tutorial_mode_ != profiles::TUTORIAL_MODE_CONFIRM_SIGNIN); 733 DismissTutorial(); 734 } else if (sender == tutorial_see_whats_new_button_) { 735 ProfileMetrics::LogProfileNewAvatarMenuUpgrade( 736 ProfileMetrics::PROFILE_AVATAR_MENU_UPGRADE_WHATS_NEW); 737 chrome::ShowUserManagerWithTutorial( 738 profiles::USER_MANAGER_TUTORIAL_OVERVIEW); 739 } else if (sender == remove_account_button_) { 740 RemoveAccount(); 741 } else if (sender == account_removal_cancel_button_) { 742 account_id_to_remove_.clear(); 743 ShowView(profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT, avatar_menu_.get()); 744 } else if (sender == gaia_signin_cancel_button_) { 745 std::string primary_account = 746 SigninManagerFactory::GetForProfile(browser_->profile())-> 747 GetAuthenticatedUsername(); 748 // The account management view is only available with the 749 // --enable-account-consistency flag. 750 bool account_management_available = !primary_account.empty() && 751 switches::IsEnableAccountConsistency(); 752 ShowView(account_management_available ? 753 profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT : 754 profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER, avatar_menu_.get()); 755 } else if (sender == current_profile_photo_) { 756 avatar_menu_->EditProfile(avatar_menu_->GetActiveProfileIndex()); 757 PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_EDIT_IMAGE); 758 } else if (sender == signin_current_profile_link_) { 759 ShowView(profiles::BUBBLE_VIEW_MODE_GAIA_SIGNIN, avatar_menu_.get()); 760 } else if (sender == add_person_button_) { 761 ProfileMetrics::LogProfileNewAvatarMenuNotYou( 762 ProfileMetrics::PROFILE_AVATAR_MENU_NOT_YOU_ADD_PERSON); 763 chrome::ShowUserManager(browser_->profile()->GetPath()); 764 } else if (sender == disconnect_button_) { 765 ProfileMetrics::LogProfileNewAvatarMenuNotYou( 766 ProfileMetrics::PROFILE_AVATAR_MENU_NOT_YOU_DISCONNECT); 767 chrome::ShowSettings(browser_); 768 } else if (sender == switch_user_cancel_button_) { 769 ShowView(profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER, avatar_menu_.get()); 770 ProfileMetrics::LogProfileNewAvatarMenuNotYou( 771 ProfileMetrics::PROFILE_AVATAR_MENU_NOT_YOU_BACK); 772 } else { 773 // Either one of the "other profiles", or one of the profile accounts 774 // buttons was pressed. 775 ButtonIndexes::const_iterator profile_match = 776 open_other_profile_indexes_map_.find(sender); 777 if (profile_match != open_other_profile_indexes_map_.end()) { 778 avatar_menu_->SwitchToProfile( 779 profile_match->second, 780 ui::DispositionFromEventFlags(event.flags()) == NEW_WINDOW, 781 ProfileMetrics::SWITCH_PROFILE_ICON); 782 } else { 783 // This was a profile accounts button. 784 AccountButtonIndexes::const_iterator account_match = 785 delete_account_button_map_.find(sender); 786 if (account_match != delete_account_button_map_.end()) { 787 account_id_to_remove_ = account_match->second; 788 ShowView(profiles::BUBBLE_VIEW_MODE_ACCOUNT_REMOVAL, 789 avatar_menu_.get()); 790 } else { 791 account_match = reauth_account_button_map_.find(sender); 792 DCHECK(account_match != reauth_account_button_map_.end()); 793 ShowView(profiles::BUBBLE_VIEW_MODE_GAIA_REAUTH, avatar_menu_.get()); 794 } 795 } 796 } 797} 798 799void ProfileChooserView::RemoveAccount() { 800 DCHECK(!account_id_to_remove_.empty()); 801 MutableProfileOAuth2TokenService* oauth2_token_service = 802 ProfileOAuth2TokenServiceFactory::GetPlatformSpecificForProfile( 803 browser_->profile()); 804 if (oauth2_token_service) { 805 oauth2_token_service->RevokeCredentials(account_id_to_remove_); 806 PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_REMOVE_ACCT); 807 } 808 account_id_to_remove_.clear(); 809 810 ShowView(profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT, avatar_menu_.get()); 811} 812 813void ProfileChooserView::LinkClicked(views::Link* sender, int event_flags) { 814 if (sender == manage_accounts_link_) { 815 // This link can either mean show/hide the account management view, 816 // depending on which view it is displayed. ShowView() will DCHECK if 817 // the account management view is displayed for non signed-in users. 818 ShowView( 819 view_mode_ == profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT ? 820 profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER : 821 profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT, 822 avatar_menu_.get()); 823 } else if (sender == add_account_link_) { 824 ShowView(profiles::BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT, avatar_menu_.get()); 825 PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_ADD_ACCT); 826 } else if (sender == tutorial_sync_settings_link_) { 827 LoginUIServiceFactory::GetForProfile(browser_->profile())-> 828 SyncConfirmationUIClosed(true /* configure_sync_first */); 829 tutorial_mode_ = profiles::TUTORIAL_MODE_NONE; 830 ProfileMetrics::LogProfileNewAvatarMenuSignin( 831 ProfileMetrics::PROFILE_AVATAR_MENU_SIGNIN_SETTINGS); 832 } else if (sender == tutorial_not_you_link_){ 833 ProfileMetrics::LogProfileNewAvatarMenuUpgrade( 834 ProfileMetrics::PROFILE_AVATAR_MENU_UPGRADE_NOT_YOU); 835 ShowView(profiles::BUBBLE_VIEW_MODE_SWITCH_USER, avatar_menu_.get()); 836 } else { 837 DCHECK(sender == tutorial_learn_more_link_); 838 signin_ui_util::ShowSigninErrorLearnMorePage(browser_->profile()); 839 } 840} 841 842void ProfileChooserView::StyledLabelLinkClicked( 843 const gfx::Range& range, int event_flags) { 844 chrome::ShowSettings(browser_); 845} 846 847bool ProfileChooserView::HandleKeyEvent(views::Textfield* sender, 848 const ui::KeyEvent& key_event) { 849 views::Textfield* name_textfield = 850 current_profile_name_->profile_name_textfield(); 851 DCHECK(sender == name_textfield); 852 853 if (key_event.key_code() == ui::VKEY_RETURN || 854 key_event.key_code() == ui::VKEY_TAB) { 855 // Pressing Tab/Enter commits the new profile name, unless it's empty. 856 base::string16 new_profile_name = name_textfield->text(); 857 base::TrimWhitespace(new_profile_name, base::TRIM_ALL, &new_profile_name); 858 if (new_profile_name.empty()) 859 return true; 860 861 const AvatarMenu::Item& active_item = avatar_menu_->GetItemAt( 862 avatar_menu_->GetActiveProfileIndex()); 863 Profile* profile = g_browser_process->profile_manager()->GetProfile( 864 active_item.profile_path); 865 DCHECK(profile); 866 867 if (profile->IsSupervised()) 868 return true; 869 870 profiles::UpdateProfileName(profile, new_profile_name); 871 PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_EDIT_NAME); 872 current_profile_name_->ShowReadOnlyView(); 873 return true; 874 } 875 return false; 876} 877 878views::View* ProfileChooserView::CreateProfileChooserView( 879 AvatarMenu* avatar_menu) { 880 views::View* view = new views::View(); 881 views::GridLayout* layout = CreateSingleColumnLayout(view, kFixedMenuWidth); 882 // Separate items into active and alternatives. 883 Indexes other_profiles; 884 views::View* tutorial_view = NULL; 885 views::View* current_profile_view = NULL; 886 views::View* current_profile_accounts = NULL; 887 views::View* option_buttons_view = NULL; 888 for (size_t i = 0; i < avatar_menu->GetNumberOfItems(); ++i) { 889 const AvatarMenu::Item& item = avatar_menu->GetItemAt(i); 890 if (item.active) { 891 option_buttons_view = CreateOptionsView( 892 switches::IsNewProfileManagement() && item.signed_in); 893 current_profile_view = CreateCurrentProfileView(item, false); 894 if (view_mode_ == profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER) { 895 switch (tutorial_mode_) { 896 case profiles::TUTORIAL_MODE_NONE: 897 case profiles::TUTORIAL_MODE_WELCOME_UPGRADE: 898 tutorial_view = CreateWelcomeUpgradeTutorialViewIfNeeded( 899 tutorial_mode_ == profiles::TUTORIAL_MODE_WELCOME_UPGRADE, 900 item); 901 break; 902 case profiles::TUTORIAL_MODE_CONFIRM_SIGNIN: 903 tutorial_view = CreateSigninConfirmationView(); 904 break; 905 case profiles::TUTORIAL_MODE_SHOW_ERROR: 906 tutorial_view = CreateSigninErrorView(); 907 break; 908 } 909 } else { 910 current_profile_accounts = CreateCurrentProfileAccountsView(item); 911 } 912 } else { 913 other_profiles.push_back(i); 914 } 915 } 916 917 if (tutorial_view) { 918 // TODO(mlerman): update UMA stats for the new tutorial. 919 layout->StartRow(1, 0); 920 layout->AddView(tutorial_view); 921 } else { 922 tutorial_mode_ = profiles::TUTORIAL_MODE_NONE; 923 } 924 925 if (!current_profile_view) { 926 // Guest windows don't have an active profile. 927 current_profile_view = CreateGuestProfileView(); 928 option_buttons_view = CreateOptionsView(false); 929 } 930 931 layout->StartRow(1, 0); 932 layout->AddView(current_profile_view); 933 934 if (view_mode_ != profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER) { 935 DCHECK(current_profile_accounts); 936 layout->StartRow(0, 0); 937 layout->AddView(new views::Separator(views::Separator::HORIZONTAL)); 938 layout->StartRow(1, 0); 939 layout->AddView(current_profile_accounts); 940 } 941 942 if (browser_->profile()->IsSupervised()) { 943 layout->StartRow(0, 0); 944 layout->AddView(new views::Separator(views::Separator::HORIZONTAL)); 945 layout->StartRow(1, 0); 946 layout->AddView(CreateSupervisedUserDisclaimerView()); 947 } 948 949 if (view_mode_ == profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER) { 950 layout->StartRow(1, 0); 951 if (switches::IsFastUserSwitching()) 952 layout->AddView(CreateOtherProfilesView(other_profiles)); 953 } 954 955 layout->StartRow(0, 0); 956 layout->AddView(new views::Separator(views::Separator::HORIZONTAL)); 957 958 if (option_buttons_view) { 959 layout->StartRow(0, 0); 960 layout->AddView(option_buttons_view); 961 } 962 963 return view; 964} 965 966void ProfileChooserView::DismissTutorial() { 967 // Never shows the upgrade tutorial again if manually closed. 968 if (tutorial_mode_ == profiles::TUTORIAL_MODE_WELCOME_UPGRADE) { 969 browser_->profile()->GetPrefs()->SetInteger( 970 prefs::kProfileAvatarTutorialShown, 971 signin_ui_util::kUpgradeWelcomeTutorialShowMax + 1); 972 } 973 974 tutorial_mode_ = profiles::TUTORIAL_MODE_NONE; 975 ShowView(profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER, avatar_menu_.get()); 976} 977 978views::View* ProfileChooserView::CreateTutorialView( 979 profiles::TutorialMode tutorial_mode, 980 const base::string16& title_text, 981 const base::string16& content_text, 982 const base::string16& link_text, 983 const base::string16& button_text, 984 bool stack_button, 985 views::Link** link, 986 views::LabelButton** button, 987 views::ImageButton** close_button) { 988 tutorial_mode_ = tutorial_mode; 989 990 views::View* view = new views::View(); 991 view->set_background(views::Background::CreateSolidBackground( 992 profiles::kAvatarTutorialBackgroundColor)); 993 views::GridLayout* layout = CreateSingleColumnLayout(view, 994 kFixedMenuWidth - 2 * views::kButtonHEdgeMarginNew); 995 // Creates a second column set for buttons and links. 996 views::ColumnSet* button_columns = layout->AddColumnSet(1); 997 button_columns->AddColumn(views::GridLayout::LEADING, 998 views::GridLayout::CENTER, 0, views::GridLayout::USE_PREF, 0, 0); 999 button_columns->AddPaddingColumn( 1000 1, views::kUnrelatedControlHorizontalSpacing); 1001 button_columns->AddColumn(views::GridLayout::TRAILING, 1002 views::GridLayout::CENTER, 0, views::GridLayout::USE_PREF, 0, 0); 1003 layout->SetInsets(views::kButtonVEdgeMarginNew, 1004 views::kButtonHEdgeMarginNew, 1005 views::kButtonVEdgeMarginNew, 1006 views::kButtonHEdgeMarginNew); 1007 1008 // Adds title and close button if needed. 1009 views::Label* title_label = new views::Label(title_text); 1010 title_label->SetMultiLine(true); 1011 title_label->SetHorizontalAlignment(gfx::ALIGN_LEFT); 1012 title_label->SetAutoColorReadabilityEnabled(false); 1013 title_label->SetEnabledColor(SK_ColorWHITE); 1014 title_label->SetFontList(ui::ResourceBundle::GetSharedInstance().GetFontList( 1015 ui::ResourceBundle::MediumFont)); 1016 1017 if (close_button) { 1018 layout->StartRow(1, 1); 1019 layout->AddView(title_label); 1020 *close_button = new views::ImageButton(this); 1021 (*close_button)->SetImageAlignment(views::ImageButton::ALIGN_RIGHT, 1022 views::ImageButton::ALIGN_MIDDLE); 1023 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance(); 1024 (*close_button)->SetImage(views::ImageButton::STATE_NORMAL, 1025 rb->GetImageSkiaNamed(IDR_CLOSE_1)); 1026 (*close_button)->SetImage(views::ImageButton::STATE_HOVERED, 1027 rb->GetImageSkiaNamed(IDR_CLOSE_1_H)); 1028 (*close_button)->SetImage(views::ImageButton::STATE_PRESSED, 1029 rb->GetImageSkiaNamed(IDR_CLOSE_1_P)); 1030 layout->AddView(*close_button); 1031 } else { 1032 layout->StartRow(1, 0); 1033 layout->AddView(title_label); 1034 } 1035 1036 // Adds body content. 1037 views::Label* content_label = new views::Label(content_text); 1038 content_label->SetMultiLine(true); 1039 content_label->SetHorizontalAlignment(gfx::ALIGN_LEFT); 1040 content_label->SetAutoColorReadabilityEnabled(false); 1041 content_label->SetEnabledColor(profiles::kAvatarTutorialContentTextColor); 1042 layout->StartRowWithPadding(1, 0, 0, views::kRelatedControlVerticalSpacing); 1043 layout->AddView(content_label); 1044 1045 // Adds links and buttons. 1046 bool has_button = !button_text.empty(); 1047 if (has_button) { 1048 *button = new views::LabelButton(this, button_text); 1049 (*button)->SetHorizontalAlignment(gfx::ALIGN_CENTER); 1050 (*button)->SetStyle(views::Button::STYLE_BUTTON); 1051 } 1052 1053 bool has_link = !link_text.empty(); 1054 if (has_link) { 1055 *link = CreateLink(link_text, this); 1056 (*link)->SetHorizontalAlignment(gfx::ALIGN_LEFT); 1057 (*link)->SetAutoColorReadabilityEnabled(false); 1058 (*link)->SetEnabledColor(SK_ColorWHITE); 1059 } 1060 1061 if (stack_button) { 1062 DCHECK(has_button); 1063 layout->StartRowWithPadding( 1064 1, 0, 0, views::kUnrelatedControlVerticalSpacing); 1065 layout->AddView(*button); 1066 if (has_link) { 1067 layout->StartRowWithPadding( 1068 1, 0, 0, views::kRelatedControlVerticalSpacing); 1069 (*link)->SetHorizontalAlignment(gfx::ALIGN_CENTER); 1070 layout->AddView(*link); 1071 } 1072 } else { 1073 DCHECK(has_link || has_button); 1074 layout->StartRowWithPadding( 1075 1, 1, 0, views::kUnrelatedControlVerticalSpacing); 1076 if (has_link) 1077 layout->AddView(*link); 1078 else 1079 layout->SkipColumns(1); 1080 if (has_button) 1081 layout->AddView(*button); 1082 else 1083 layout->SkipColumns(1); 1084 } 1085 1086 return view; 1087} 1088 1089views::View* ProfileChooserView::CreateCurrentProfileView( 1090 const AvatarMenu::Item& avatar_item, 1091 bool is_guest) { 1092 views::View* view = new views::View(); 1093 int column_width = kFixedMenuWidth - 2 * views::kButtonHEdgeMarginNew; 1094 views::GridLayout* layout = CreateSingleColumnLayout(view, column_width); 1095 layout->SetInsets(views::kButtonVEdgeMarginNew, 1096 views::kButtonHEdgeMarginNew, 1097 views::kUnrelatedControlVerticalSpacing, 1098 views::kButtonHEdgeMarginNew); 1099 1100 // Profile icon, centered. 1101 int x_offset = (column_width - kLargeImageSide) / 2; 1102 current_profile_photo_ = new EditableProfilePhoto( 1103 this, avatar_item.icon, !is_guest, 1104 gfx::Rect(x_offset, 0, kLargeImageSide, kLargeImageSide)); 1105 SizedContainer* profile_icon_container = 1106 new SizedContainer(gfx::Size(column_width, kLargeImageSide)); 1107 profile_icon_container->AddChildView(current_profile_photo_); 1108 1109 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance(); 1110 if (browser_->profile()->IsSupervised()) { 1111 views::ImageView* supervised_icon = new views::ImageView(); 1112 supervised_icon->SetImage( 1113 rb->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_SUPERVISED)); 1114 gfx::Size preferred_size = supervised_icon->GetPreferredSize(); 1115 gfx::Rect parent_bounds = current_profile_photo_->bounds(); 1116 supervised_icon->SetBounds( 1117 parent_bounds.right() - preferred_size.width(), 1118 parent_bounds.bottom() - preferred_size.height(), 1119 preferred_size.width(), 1120 preferred_size.height()); 1121 profile_icon_container->AddChildView(supervised_icon); 1122 } 1123 1124 layout->StartRow(1, 0); 1125 layout->AddView(profile_icon_container); 1126 1127 // Profile name, centered. 1128 bool editing_allowed = !is_guest && !browser_->profile()->IsSupervised(); 1129 current_profile_name_ = new EditableProfileName( 1130 this, 1131 profiles::GetAvatarNameForProfile(browser_->profile()->GetPath()), 1132 editing_allowed); 1133 layout->StartRowWithPadding(1, 0, 0, 1134 views::kRelatedControlSmallVerticalSpacing); 1135 layout->StartRow(1, 0); 1136 layout->AddView(current_profile_name_); 1137 1138 if (is_guest) 1139 return view; 1140 1141 // The available links depend on the type of profile that is active. 1142 if (avatar_item.signed_in) { 1143 layout->StartRow(1, 0); 1144 if (switches::IsEnableAccountConsistency()) { 1145 base::string16 link_title = l10n_util::GetStringUTF16( 1146 view_mode_ == profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER ? 1147 IDS_PROFILES_PROFILE_MANAGE_ACCOUNTS_BUTTON : 1148 IDS_PROFILES_PROFILE_HIDE_MANAGE_ACCOUNTS_BUTTON); 1149 manage_accounts_link_ = CreateLink(link_title, this); 1150 manage_accounts_link_->SetHorizontalAlignment(gfx::ALIGN_CENTER); 1151 layout->AddView(manage_accounts_link_); 1152 } else { 1153 // Add a small padding between the email button and the profile name. 1154 layout->StartRowWithPadding(1, 0, 0, 2); 1155 // Badge the email address if there's an authentication error. 1156 if (HasAuthError(browser_->profile())) { 1157 const gfx::ImageSkia warning_image = *rb->GetImageNamed( 1158 IDR_ICON_PROFILES_ACCOUNT_BUTTON_ERROR).ToImageSkia(); 1159 auth_error_email_button_ = 1160 new RightAlignedIconLabelButton(this, avatar_item.sync_state); 1161 auth_error_email_button_->SetElideBehavior(gfx::ELIDE_EMAIL); 1162 auth_error_email_button_->SetBorder(views::Border::NullBorder()); 1163 auth_error_email_button_->SetImage( 1164 views::LabelButton::STATE_NORMAL, warning_image); 1165 auth_error_email_button_->SetTextColor( 1166 views::LabelButton::STATE_NORMAL, 1167 views::Link::GetDefaultEnabledColor()); 1168 auth_error_email_button_->SetFocusable(true); 1169 layout->AddView(auth_error_email_button_); 1170 } else { 1171 views::Label* email_label = new views::Label(avatar_item.sync_state); 1172 email_label->SetElideBehavior(gfx::ELIDE_EMAIL); 1173 email_label->SetEnabled(false); 1174 layout->AddView(email_label); 1175 } 1176 } 1177 } else { 1178 SigninManagerBase* signin_manager = SigninManagerFactory::GetForProfile( 1179 browser_->profile()->GetOriginalProfile()); 1180 if (signin_manager->IsSigninAllowed()) { 1181 views::Label* promo = new views::Label( 1182 l10n_util::GetStringUTF16(IDS_PROFILES_SIGNIN_PROMO)); 1183 promo->SetMultiLine(true); 1184 promo->SetHorizontalAlignment(gfx::ALIGN_LEFT); 1185 layout->StartRowWithPadding(1, 0, 0, 1186 views::kRelatedControlSmallVerticalSpacing); 1187 layout->StartRow(1, 0); 1188 layout->AddView(promo); 1189 1190 signin_current_profile_link_ = new views::BlueButton( 1191 this, l10n_util::GetStringFUTF16(IDS_SYNC_START_SYNC_BUTTON_LABEL, 1192 l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME))); 1193 layout->StartRowWithPadding(1, 0, 0, 1194 views::kRelatedControlVerticalSpacing); 1195 layout->StartRow(1, 0); 1196 layout->AddView(signin_current_profile_link_); 1197 } 1198 } 1199 1200 return view; 1201} 1202 1203views::View* ProfileChooserView::CreateGuestProfileView() { 1204 gfx::Image guest_icon = 1205 ui::ResourceBundle::GetSharedInstance().GetImageNamed( 1206 profiles::GetPlaceholderAvatarIconResourceID()); 1207 AvatarMenu::Item guest_avatar_item(0, 0, guest_icon); 1208 guest_avatar_item.active = true; 1209 guest_avatar_item.name = l10n_util::GetStringUTF16( 1210 IDS_PROFILES_GUEST_PROFILE_NAME); 1211 guest_avatar_item.signed_in = false; 1212 1213 return CreateCurrentProfileView(guest_avatar_item, true); 1214} 1215 1216views::View* ProfileChooserView::CreateOtherProfilesView( 1217 const Indexes& avatars_to_show) { 1218 views::View* view = new views::View(); 1219 views::GridLayout* layout = CreateSingleColumnLayout(view, kFixedMenuWidth); 1220 1221 int num_avatars_to_show = avatars_to_show.size(); 1222 for (int i = 0; i < num_avatars_to_show; ++i) { 1223 const size_t index = avatars_to_show[i]; 1224 const AvatarMenu::Item& item = avatar_menu_->GetItemAt(index); 1225 const int kSmallImageSide = 32; 1226 1227 gfx::Image image = profiles::GetSizedAvatarIcon( 1228 item.icon, true, kSmallImageSide, kSmallImageSide); 1229 1230 views::LabelButton* button = new BackgroundColorHoverButton( 1231 this, 1232 item.name, 1233 *image.ToImageSkia()); 1234 open_other_profile_indexes_map_[button] = index; 1235 1236 layout->StartRow(1, 0); 1237 layout->AddView(new views::Separator(views::Separator::HORIZONTAL)); 1238 layout->StartRow(1, 0); 1239 layout->AddView(button); 1240 } 1241 1242 return view; 1243} 1244 1245views::View* ProfileChooserView::CreateOptionsView(bool enable_lock) { 1246 views::View* view = new views::View(); 1247 views::GridLayout* layout = CreateSingleColumnLayout(view, kFixedMenuWidth); 1248 1249 base::string16 text = browser_->profile()->IsGuestSession() ? 1250 l10n_util::GetStringUTF16(IDS_PROFILES_EXIT_GUEST) : 1251 l10n_util::GetStringUTF16(IDS_PROFILES_SWITCH_USERS_BUTTON); 1252 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance(); 1253 users_button_ = new BackgroundColorHoverButton( 1254 this, 1255 text, 1256 *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_AVATAR)); 1257 layout->StartRow(1, 0); 1258 layout->AddView(users_button_); 1259 1260 if (ShouldShowGoIncognito()) { 1261 layout->StartRow(1, 0); 1262 layout->AddView(new views::Separator(views::Separator::HORIZONTAL)); 1263 1264 go_incognito_button_ = new BackgroundColorHoverButton( 1265 this, 1266 l10n_util::GetStringUTF16(IDS_PROFILES_GO_INCOGNITO_BUTTON), 1267 *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_INCOGNITO)); 1268 layout->StartRow(1, 0); 1269 layout->AddView(go_incognito_button_); 1270 } 1271 1272 if (enable_lock) { 1273 layout->StartRow(1, 0); 1274 layout->AddView(new views::Separator(views::Separator::HORIZONTAL)); 1275 1276 lock_button_ = new BackgroundColorHoverButton( 1277 this, 1278 l10n_util::GetStringUTF16(IDS_PROFILES_PROFILE_SIGNOUT_BUTTON), 1279 *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_LOCK)); 1280 layout->StartRow(1, 0); 1281 layout->AddView(lock_button_); 1282 } 1283 return view; 1284} 1285 1286views::View* ProfileChooserView::CreateSupervisedUserDisclaimerView() { 1287 views::View* view = new views::View(); 1288 views::GridLayout* layout = CreateSingleColumnLayout( 1289 view, kFixedMenuWidth - 2 * views::kButtonHEdgeMarginNew); 1290 layout->SetInsets(views::kRelatedControlVerticalSpacing, 1291 views::kButtonHEdgeMarginNew, 1292 views::kRelatedControlVerticalSpacing, 1293 views::kButtonHEdgeMarginNew); 1294 views::Label* disclaimer = new views::Label( 1295 avatar_menu_->GetSupervisedUserInformation()); 1296 disclaimer->SetMultiLine(true); 1297 disclaimer->SetHorizontalAlignment(gfx::ALIGN_LEFT); 1298 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance(); 1299 disclaimer->SetFontList(rb->GetFontList(ui::ResourceBundle::SmallFont)); 1300 layout->StartRow(1, 0); 1301 layout->AddView(disclaimer); 1302 1303 return view; 1304} 1305 1306views::View* ProfileChooserView::CreateCurrentProfileAccountsView( 1307 const AvatarMenu::Item& avatar_item) { 1308 DCHECK(avatar_item.signed_in); 1309 views::View* view = new views::View(); 1310 view->set_background(views::Background::CreateSolidBackground( 1311 profiles::kAvatarBubbleAccountsBackgroundColor)); 1312 views::GridLayout* layout = CreateSingleColumnLayout(view, kFixedMenuWidth); 1313 1314 Profile* profile = browser_->profile(); 1315 std::string primary_account = 1316 SigninManagerFactory::GetForProfile(profile)->GetAuthenticatedUsername(); 1317 DCHECK(!primary_account.empty()); 1318 std::vector<std::string>accounts = 1319 profiles::GetSecondaryAccountsForProfile(profile, primary_account); 1320 1321 // Get state of authentication error, if any. 1322 std::string error_account_id = GetAuthErrorAccountId(profile); 1323 1324 // The primary account should always be listed first. 1325 // TODO(rogerta): we still need to further differentiate the primary account 1326 // from the others in the UI, so more work is likely required here: 1327 // crbug.com/311124. 1328 CreateAccountButton(layout, primary_account, true, 1329 error_account_id == primary_account, kFixedMenuWidth); 1330 for (size_t i = 0; i < accounts.size(); ++i) 1331 CreateAccountButton(layout, accounts[i], false, 1332 error_account_id == accounts[i], kFixedMenuWidth); 1333 1334 if (!profile->IsSupervised()) { 1335 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); 1336 1337 add_account_link_ = CreateLink(l10n_util::GetStringFUTF16( 1338 IDS_PROFILES_PROFILE_ADD_ACCOUNT_BUTTON, avatar_item.name), this); 1339 add_account_link_->SetBorder(views::Border::CreateEmptyBorder( 1340 0, views::kButtonVEdgeMarginNew, 1341 views::kRelatedControlVerticalSpacing, 0)); 1342 layout->StartRow(1, 0); 1343 layout->AddView(add_account_link_); 1344 } 1345 1346 return view; 1347} 1348 1349void ProfileChooserView::CreateAccountButton(views::GridLayout* layout, 1350 const std::string& account, 1351 bool is_primary_account, 1352 bool reauth_required, 1353 int width) { 1354 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance(); 1355 const gfx::ImageSkia* delete_default_image = 1356 rb->GetImageNamed(IDR_CLOSE_1).ToImageSkia(); 1357 const int kDeleteButtonWidth = delete_default_image->width(); 1358 const gfx::ImageSkia warning_default_image = reauth_required ? 1359 *rb->GetImageNamed(IDR_ICON_PROFILES_ACCOUNT_BUTTON_ERROR).ToImageSkia() : 1360 gfx::ImageSkia(); 1361 const int kWarningButtonWidth = reauth_required ? 1362 warning_default_image.width() + views::kRelatedButtonHSpacing : 0; 1363 int available_width = width - 2 * views::kButtonHEdgeMarginNew 1364 - kDeleteButtonWidth - kWarningButtonWidth; 1365 views::LabelButton* email_button = new BackgroundColorHoverButton( 1366 reauth_required ? this : NULL, 1367 base::UTF8ToUTF16(account), 1368 warning_default_image); 1369 email_button->SetElideBehavior(gfx::ELIDE_EMAIL); 1370 email_button->SetMinSize(gfx::Size(0, kButtonHeight)); 1371 email_button->SetMaxSize(gfx::Size(available_width, kButtonHeight)); 1372 layout->StartRow(1, 0); 1373 layout->AddView(email_button); 1374 1375 if (reauth_required) 1376 reauth_account_button_map_[email_button] = account; 1377 1378 // Delete button. 1379 if (!browser_->profile()->IsSupervised()) { 1380 views::ImageButton* delete_button = new views::ImageButton(this); 1381 delete_button->SetImageAlignment(views::ImageButton::ALIGN_RIGHT, 1382 views::ImageButton::ALIGN_MIDDLE); 1383 delete_button->SetImage(views::ImageButton::STATE_NORMAL, 1384 delete_default_image); 1385 delete_button->SetImage(views::ImageButton::STATE_HOVERED, 1386 rb->GetImageSkiaNamed(IDR_CLOSE_1_H)); 1387 delete_button->SetImage(views::ImageButton::STATE_PRESSED, 1388 rb->GetImageSkiaNamed(IDR_CLOSE_1_P)); 1389 delete_button->SetBounds( 1390 width - views::kButtonHEdgeMarginNew - kDeleteButtonWidth, 1391 0, kDeleteButtonWidth, kButtonHeight); 1392 1393 email_button->set_notify_enter_exit_on_child(true); 1394 email_button->AddChildView(delete_button); 1395 1396 // Save the original email address, as the button text could be elided. 1397 delete_account_button_map_[delete_button] = account; 1398 } 1399} 1400 1401views::View* ProfileChooserView::CreateGaiaSigninView() { 1402 GURL url; 1403 int message_id; 1404 1405 switch (view_mode_) { 1406 case profiles::BUBBLE_VIEW_MODE_GAIA_SIGNIN: 1407 url = signin::GetPromoURL(signin::SOURCE_AVATAR_BUBBLE_SIGN_IN, 1408 false /* auto_close */, 1409 true /* is_constrained */); 1410 message_id = IDS_PROFILES_GAIA_SIGNIN_TITLE; 1411 break; 1412 case profiles::BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT: 1413 url = signin::GetPromoURL(signin::SOURCE_AVATAR_BUBBLE_ADD_ACCOUNT, 1414 false /* auto_close */, 1415 true /* is_constrained */); 1416 message_id = IDS_PROFILES_GAIA_ADD_ACCOUNT_TITLE; 1417 break; 1418 case profiles::BUBBLE_VIEW_MODE_GAIA_REAUTH: { 1419 DCHECK(HasAuthError(browser_->profile())); 1420 url = signin::GetReauthURL(browser_->profile(), 1421 GetAuthErrorUsername(browser_->profile())); 1422 message_id = IDS_PROFILES_GAIA_REAUTH_TITLE; 1423 break; 1424 } 1425 default: 1426 NOTREACHED() << "Called with invalid mode=" << view_mode_; 1427 return NULL; 1428 } 1429 1430 // Adds Gaia signin webview 1431 Profile* profile = browser_->profile(); 1432 views::WebView* web_view = new views::WebView(profile); 1433 web_view->LoadInitialURL(url); 1434 web_view->SetPreferredSize( 1435 gfx::Size(kFixedGaiaViewWidth, kFixedGaiaViewHeight)); 1436 1437 TitleCard* title_card = new TitleCard(l10n_util::GetStringUTF16(message_id), 1438 this, 1439 &gaia_signin_cancel_button_); 1440 return TitleCard::AddPaddedTitleCard( 1441 web_view, title_card, kFixedGaiaViewWidth); 1442} 1443 1444views::View* ProfileChooserView::CreateAccountRemovalView() { 1445 views::View* view = new views::View(); 1446 views::GridLayout* layout = CreateSingleColumnLayout( 1447 view, kFixedAccountRemovalViewWidth - 2 * views::kButtonHEdgeMarginNew); 1448 layout->SetInsets(0, 1449 views::kButtonHEdgeMarginNew, 1450 views::kButtonVEdgeMarginNew, 1451 views::kButtonHEdgeMarginNew); 1452 1453 const std::string& primary_account = SigninManagerFactory::GetForProfile( 1454 browser_->profile())->GetAuthenticatedUsername(); 1455 bool is_primary_account = primary_account == account_id_to_remove_; 1456 1457 // Adds main text. 1458 layout->StartRowWithPadding(1, 0, 0, views::kUnrelatedControlVerticalSpacing); 1459 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance(); 1460 const gfx::FontList& small_font_list = 1461 rb->GetFontList(ui::ResourceBundle::SmallFont); 1462 1463 if (is_primary_account) { 1464 std::vector<size_t> offsets; 1465 const base::string16 settings_text = 1466 l10n_util::GetStringUTF16(IDS_PROFILES_SETTINGS_LINK); 1467 const base::string16 primary_account_removal_text = 1468 l10n_util::GetStringFUTF16(IDS_PROFILES_PRIMARY_ACCOUNT_REMOVAL_TEXT, 1469 base::UTF8ToUTF16(account_id_to_remove_), settings_text, &offsets); 1470 views::StyledLabel* primary_account_removal_label = 1471 new views::StyledLabel(primary_account_removal_text, this); 1472 primary_account_removal_label->AddStyleRange( 1473 gfx::Range(offsets[1], offsets[1] + settings_text.size()), 1474 views::StyledLabel::RangeStyleInfo::CreateForLink()); 1475 primary_account_removal_label->SetBaseFontList(small_font_list); 1476 layout->AddView(primary_account_removal_label); 1477 } else { 1478 views::Label* content_label = new views::Label( 1479 l10n_util::GetStringUTF16(IDS_PROFILES_ACCOUNT_REMOVAL_TEXT)); 1480 content_label->SetMultiLine(true); 1481 content_label->SetHorizontalAlignment(gfx::ALIGN_LEFT); 1482 content_label->SetFontList(small_font_list); 1483 layout->AddView(content_label); 1484 } 1485 1486 // Adds button. 1487 if (!is_primary_account) { 1488 remove_account_button_ = new views::BlueButton( 1489 this, l10n_util::GetStringUTF16(IDS_PROFILES_ACCOUNT_REMOVAL_BUTTON)); 1490 remove_account_button_->SetHorizontalAlignment( 1491 gfx::ALIGN_CENTER); 1492 layout->StartRowWithPadding( 1493 1, 0, 0, views::kUnrelatedControlVerticalSpacing); 1494 layout->AddView(remove_account_button_); 1495 } else { 1496 layout->AddPaddingRow(0, views::kUnrelatedControlVerticalSpacing); 1497 } 1498 1499 TitleCard* title_card = new TitleCard( 1500 l10n_util::GetStringUTF16(IDS_PROFILES_ACCOUNT_REMOVAL_TITLE), 1501 this, &account_removal_cancel_button_); 1502 return TitleCard::AddPaddedTitleCard(view, title_card, 1503 kFixedAccountRemovalViewWidth); 1504} 1505 1506views::View* ProfileChooserView::CreateWelcomeUpgradeTutorialViewIfNeeded( 1507 bool tutorial_shown, const AvatarMenu::Item& avatar_item){ 1508 Profile* profile = browser_->profile(); 1509 1510 const int show_count = profile->GetPrefs()->GetInteger( 1511 prefs::kProfileAvatarTutorialShown); 1512 // Do not show the tutorial if user has dismissed it. 1513 if (show_count > signin_ui_util::kUpgradeWelcomeTutorialShowMax) 1514 return NULL; 1515 1516 if (!tutorial_shown) { 1517 if (show_count == signin_ui_util::kUpgradeWelcomeTutorialShowMax) 1518 return NULL; 1519 profile->GetPrefs()->SetInteger( 1520 prefs::kProfileAvatarTutorialShown, show_count + 1); 1521 } 1522 ProfileMetrics::LogProfileNewAvatarMenuUpgrade( 1523 ProfileMetrics::PROFILE_AVATAR_MENU_UPGRADE_VIEW); 1524 1525 // For local profiles, the "Not you" link doesn't make sense. 1526 base::string16 link_message = avatar_item.signed_in ? 1527 l10n_util::GetStringFUTF16(IDS_PROFILES_NOT_YOU, avatar_item.name) : 1528 base::string16(); 1529 1530 return CreateTutorialView( 1531 profiles::TUTORIAL_MODE_WELCOME_UPGRADE, 1532 l10n_util::GetStringUTF16( 1533 IDS_PROFILES_WELCOME_UPGRADE_TUTORIAL_TITLE), 1534 l10n_util::GetStringUTF16( 1535 IDS_PROFILES_WELCOME_UPGRADE_TUTORIAL_CONTENT_TEXT), 1536 link_message, 1537 l10n_util::GetStringUTF16(IDS_PROFILES_TUTORIAL_WHATS_NEW_BUTTON), 1538 true /* stack_button */, 1539 &tutorial_not_you_link_, 1540 &tutorial_see_whats_new_button_, 1541 &tutorial_close_button_); 1542} 1543 1544views::View* ProfileChooserView::CreateSigninConfirmationView() { 1545 ProfileMetrics::LogProfileNewAvatarMenuSignin( 1546 ProfileMetrics::PROFILE_AVATAR_MENU_SIGNIN_VIEW); 1547 1548 return CreateTutorialView( 1549 profiles::TUTORIAL_MODE_CONFIRM_SIGNIN, 1550 l10n_util::GetStringUTF16(IDS_PROFILES_CONFIRM_SIGNIN_TUTORIAL_TITLE), 1551 l10n_util::GetStringUTF16( 1552 IDS_PROFILES_CONFIRM_SIGNIN_TUTORIAL_CONTENT_TEXT), 1553 l10n_util::GetStringUTF16(IDS_PROFILES_SYNC_SETTINGS_LINK), 1554 l10n_util::GetStringUTF16(IDS_PROFILES_TUTORIAL_OK_BUTTON), 1555 false /* stack_button */, 1556 &tutorial_sync_settings_link_, 1557 &tutorial_sync_settings_ok_button_, 1558 NULL /* close_button*/); 1559} 1560 1561views::View* ProfileChooserView::CreateSigninErrorView() { 1562 LoginUIService* login_ui_service = 1563 LoginUIServiceFactory::GetForProfile(browser_->profile()); 1564 base::string16 last_login_result(login_ui_service->GetLastLoginResult()); 1565 return CreateTutorialView( 1566 profiles::TUTORIAL_MODE_SHOW_ERROR, 1567 l10n_util::GetStringUTF16(IDS_PROFILES_ERROR_TUTORIAL_TITLE), 1568 last_login_result, 1569 l10n_util::GetStringUTF16(IDS_PROFILES_PROFILE_TUTORIAL_LEARN_MORE), 1570 base::string16(), 1571 false /* stack_button */, 1572 &tutorial_learn_more_link_, 1573 NULL, 1574 &tutorial_close_button_); 1575} 1576 1577views::View* ProfileChooserView::CreateSwitchUserView() { 1578 views::View* view = new views::View(); 1579 views::GridLayout* layout = CreateSingleColumnLayout( 1580 view, kFixedSwitchUserViewWidth); 1581 views::ColumnSet* columns = layout->AddColumnSet(1); 1582 columns->AddPaddingColumn(0, views::kButtonHEdgeMarginNew); 1583 int label_width = 1584 kFixedSwitchUserViewWidth - 2 * views::kButtonHEdgeMarginNew; 1585 columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 0, 1586 views::GridLayout::FIXED, label_width, label_width); 1587 columns->AddPaddingColumn(0, views::kButtonHEdgeMarginNew); 1588 1589 // Adds main text. 1590 layout->StartRowWithPadding(1, 1, 0, views::kUnrelatedControlVerticalSpacing); 1591 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance(); 1592 const gfx::FontList& small_font_list = 1593 rb->GetFontList(ui::ResourceBundle::SmallFont); 1594 const AvatarMenu::Item& avatar_item = 1595 avatar_menu_->GetItemAt(avatar_menu_->GetActiveProfileIndex()); 1596 views::Label* content_label = new views::Label( 1597 l10n_util::GetStringFUTF16( 1598 IDS_PROFILES_NOT_YOU_CONTENT_TEXT, avatar_item.name)); 1599 content_label->SetMultiLine(true); 1600 content_label->SetHorizontalAlignment(gfx::ALIGN_LEFT); 1601 content_label->SetFontList(small_font_list); 1602 layout->AddView(content_label); 1603 1604 // Adds "Add person" button. 1605 layout->StartRowWithPadding(1, 0, 0, views::kUnrelatedControlVerticalSpacing); 1606 layout->AddView(new views::Separator(views::Separator::HORIZONTAL)); 1607 1608 add_person_button_ = new BackgroundColorHoverButton( 1609 this, 1610 l10n_util::GetStringUTF16(IDS_PROFILES_ADD_PERSON_BUTTON), 1611 *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_AVATAR)); 1612 layout->StartRow(1, 0); 1613 layout->AddView(add_person_button_); 1614 1615 // Adds "Disconnect your Google Account" button. 1616 layout->StartRow(1, 0); 1617 layout->AddView(new views::Separator(views::Separator::HORIZONTAL)); 1618 1619 disconnect_button_ = new BackgroundColorHoverButton( 1620 this, 1621 l10n_util::GetStringUTF16(IDS_PROFILES_DISCONNECT_BUTTON), 1622 *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_DISCONNECT)); 1623 layout->StartRow(1, 0); 1624 layout->AddView(disconnect_button_); 1625 1626 TitleCard* title_card = new TitleCard( 1627 l10n_util::GetStringFUTF16(IDS_PROFILES_NOT_YOU, avatar_item.name), 1628 this, &switch_user_cancel_button_); 1629 return TitleCard::AddPaddedTitleCard(view, title_card, 1630 kFixedSwitchUserViewWidth); 1631} 1632 1633bool ProfileChooserView::ShouldShowGoIncognito() const { 1634 bool incognito_available = 1635 IncognitoModePrefs::GetAvailability(browser_->profile()->GetPrefs()) != 1636 IncognitoModePrefs::DISABLED; 1637 return incognito_available && !browser_->profile()->IsGuestSession(); 1638} 1639 1640void ProfileChooserView::PostActionPerformed( 1641 ProfileMetrics::ProfileDesktopMenu action_performed) { 1642 ProfileMetrics::LogProfileDesktopMenu(action_performed, gaia_service_type_); 1643 gaia_service_type_ = signin::GAIA_SERVICE_TYPE_NONE; 1644} 1645