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