profile_chooser_view.cc revision a02191e04bc25c4935f804f2c080ae28663d096d
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/about_flags.h" 10#include "chrome/browser/browser_process.h" 11#include "chrome/browser/lifetime/application_lifetime.h" 12#include "chrome/browser/pref_service_flags_storage.h" 13#include "chrome/browser/profiles/profile_avatar_icon_util.h" 14#include "chrome/browser/profiles/profile_manager.h" 15#include "chrome/browser/profiles/profile_window.h" 16#include "chrome/browser/profiles/profiles_state.h" 17#include "chrome/browser/signin/profile_oauth2_token_service_factory.h" 18#include "chrome/browser/signin/signin_manager_factory.h" 19#include "chrome/browser/signin/signin_promo.h" 20#include "chrome/browser/ui/browser.h" 21#include "chrome/browser/ui/browser_dialogs.h" 22#include "chrome/browser/ui/chrome_pages.h" 23#include "chrome/browser/ui/singleton_tabs.h" 24#include "chrome/browser/ui/views/profiles/user_manager_view.h" 25#include "chrome/common/chrome_switches.h" 26#include "chrome/common/pref_names.h" 27#include "chrome/common/profile_management_switches.h" 28#include "chrome/common/url_constants.h" 29#include "components/signin/core/browser/mutable_profile_oauth2_token_service.h" 30#include "components/signin/core/browser/profile_oauth2_token_service.h" 31#include "components/signin/core/browser/signin_manager.h" 32#include "grit/chromium_strings.h" 33#include "grit/generated_resources.h" 34#include "grit/theme_resources.h" 35#include "third_party/skia/include/core/SkColor.h" 36#include "ui/base/l10n/l10n_util.h" 37#include "ui/base/resource/resource_bundle.h" 38#include "ui/gfx/canvas.h" 39#include "ui/gfx/image/image.h" 40#include "ui/gfx/image/image_skia.h" 41#include "ui/gfx/text_elider.h" 42#include "ui/native_theme/native_theme.h" 43#include "ui/views/controls/button/blue_button.h" 44#include "ui/views/controls/button/image_button.h" 45#include "ui/views/controls/button/label_button.h" 46#include "ui/views/controls/button/menu_button.h" 47#include "ui/views/controls/label.h" 48#include "ui/views/controls/link.h" 49#include "ui/views/controls/separator.h" 50#include "ui/views/controls/styled_label.h" 51#include "ui/views/controls/textfield/textfield.h" 52#include "ui/views/controls/webview/webview.h" 53#include "ui/views/layout/grid_layout.h" 54#include "ui/views/layout/layout_constants.h" 55#include "ui/views/widget/widget.h" 56 57namespace { 58 59// Helpers -------------------------------------------------------------------- 60 61const int kFixedMenuWidth = 250; 62const int kButtonHeight = 29; 63const int kProfileAvatarTutorialShowMax = 5; 64const int kFixedGaiaViewHeight = 400; 65const int kFixedGaiaViewWidth = 360; 66const int kFixedAccountRemovalViewWidth = 280; 67 68// Creates a GridLayout with a single column. This ensures that all the child 69// views added get auto-expanded to fill the full width of the bubble. 70views::GridLayout* CreateSingleColumnLayout(views::View* view, int width) { 71 views::GridLayout* layout = new views::GridLayout(view); 72 view->SetLayoutManager(layout); 73 74 views::ColumnSet* columns = layout->AddColumnSet(0); 75 columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 0, 76 views::GridLayout::FIXED, width, width); 77 return layout; 78} 79 80// Creates a GridLayout with two columns. 81views::GridLayout* CreateDoubleColumnLayout(views::View* view) { 82 views::GridLayout* layout = new views::GridLayout(view); 83 view->SetLayoutManager(layout); 84 85 views::ColumnSet* columns = layout->AddColumnSet(0); 86 columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 0, 87 views::GridLayout::USE_PREF, 0, 0); 88 columns->AddPaddingColumn(0, views::kUnrelatedControlLargeHorizontalSpacing); 89 columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 1, 90 views::GridLayout::USE_PREF, 0, 0); 91 return layout; 92} 93 94views::Link* CreateLink(const base::string16& link_text, 95 views::LinkListener* listener) { 96 views::Link* link_button = new views::Link(link_text); 97 link_button->SetHorizontalAlignment(gfx::ALIGN_LEFT); 98 link_button->SetUnderline(false); 99 link_button->set_listener(listener); 100 return link_button; 101} 102 103 104// BackgroundColorHoverButton ------------------------------------------------- 105 106// A custom button that allows for setting a background color when hovered over. 107class BackgroundColorHoverButton : public views::LabelButton { 108 public: 109 BackgroundColorHoverButton(views::ButtonListener* listener, 110 const base::string16& text, 111 const gfx::ImageSkia& normal_icon, 112 const gfx::ImageSkia& hover_icon); 113 virtual ~BackgroundColorHoverButton(); 114 115 private: 116 // views::LabelButton: 117 virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE; 118 119 DISALLOW_COPY_AND_ASSIGN(BackgroundColorHoverButton); 120}; 121 122BackgroundColorHoverButton::BackgroundColorHoverButton( 123 views::ButtonListener* listener, 124 const base::string16& text, 125 const gfx::ImageSkia& normal_icon, 126 const gfx::ImageSkia& hover_icon) 127 : views::LabelButton(listener, text) { 128 SetBorder(views::Border::CreateEmptyBorder(0, views::kButtonHEdgeMarginNew, 129 0, views::kButtonHEdgeMarginNew)); 130 set_min_size(gfx::Size(0, kButtonHeight)); 131 SetImage(STATE_NORMAL, normal_icon); 132 SetImage(STATE_HOVERED, hover_icon); 133 SetImage(STATE_PRESSED, hover_icon); 134} 135 136BackgroundColorHoverButton::~BackgroundColorHoverButton() {} 137 138void BackgroundColorHoverButton::OnPaint(gfx::Canvas* canvas) { 139 if ((state() == STATE_PRESSED) || (state() == STATE_HOVERED) || HasFocus()) { 140 canvas->DrawColor(GetNativeTheme()->GetSystemColor( 141 ui::NativeTheme::kColorId_MenuSeparatorColor)); 142 } 143 LabelButton::OnPaint(canvas); 144} 145 146} // namespace 147 148 149// EditableProfilePhoto ------------------------------------------------- 150 151// A custom Image control that shows a "change" button when moused over. 152class EditableProfilePhoto : public views::ImageView { 153 public: 154 EditableProfilePhoto(views::ButtonListener* listener, 155 const gfx::Image& icon, 156 bool is_editing_allowed) 157 : views::ImageView(), 158 change_photo_button_(NULL) { 159 const int kLargeImageSide = 64; 160 gfx::Image image = profiles::GetSizedAvatarIconWithBorder( 161 icon, true, 162 kLargeImageSide + profiles::kAvatarIconPadding, 163 kLargeImageSide + profiles::kAvatarIconPadding); 164 SetImage(image.ToImageSkia()); 165 166 if (!is_editing_allowed) 167 return; 168 169 set_notify_enter_exit_on_child(true); 170 171 // Button overlay that appears when hovering over the image. 172 change_photo_button_ = new views::LabelButton(listener, 173 l10n_util::GetStringUTF16(IDS_PROFILES_PROFILE_CHANGE_PHOTO_BUTTON)); 174 change_photo_button_->SetHorizontalAlignment(gfx::ALIGN_CENTER); 175 change_photo_button_->SetBorder(views::Border::NullBorder()); 176 const SkColor color = SK_ColorWHITE; 177 change_photo_button_->SetTextColor(views::Button::STATE_NORMAL, color); 178 change_photo_button_->SetTextColor(views::Button::STATE_HOVERED, color); 179 180 const SkColor kBackgroundColor = SkColorSetARGB(125, 0, 0, 0); 181 change_photo_button_->set_background( 182 views::Background::CreateSolidBackground(kBackgroundColor)); 183 // Need to take into account the border padding on the avatar. 184 const int kOverlayHeight = 20; 185 change_photo_button_->SetBounds( 186 profiles::kAvatarIconPadding, 187 kLargeImageSide - kOverlayHeight, 188 kLargeImageSide - profiles::kAvatarIconPadding, 189 kOverlayHeight); 190 change_photo_button_->SetVisible(false); 191 AddChildView(change_photo_button_); 192 } 193 194 views::LabelButton* change_photo_button() { return change_photo_button_; } 195 196 private: 197 // views::View: 198 virtual void OnMouseEntered(const ui::MouseEvent& event) OVERRIDE { 199 if (change_photo_button_) 200 change_photo_button_->SetVisible(true); 201 } 202 203 virtual void OnMouseExited(const ui::MouseEvent& event) OVERRIDE { 204 if (change_photo_button_) 205 change_photo_button_->SetVisible(false); 206 } 207 208 // Button that is shown when hovering over the image view. Can be NULL if 209 // the photo isn't allowed to be edited (e.g. for guest profiles). 210 views::LabelButton* change_photo_button_; 211 212 DISALLOW_COPY_AND_ASSIGN(EditableProfilePhoto); 213}; 214 215 216// EditableProfileName ------------------------------------------------- 217 218// A custom text control that turns into a textfield for editing when clicked. 219class EditableProfileName : public views::LabelButton, 220 public views::ButtonListener { 221 public: 222 EditableProfileName(views::TextfieldController* controller, 223 const base::string16& text, 224 bool is_editing_allowed) 225 : views::LabelButton(this, text), 226 profile_name_textfield_(NULL) { 227 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance(); 228 const gfx::FontList& medium_font_list = 229 rb->GetFontList(ui::ResourceBundle::MediumFont); 230 SetFontList(medium_font_list); 231 SetBorder(views::Border::NullBorder()); 232 233 if (!is_editing_allowed) 234 return; 235 236 SetImage(STATE_HOVERED, 237 *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_EDIT_HOVER)); 238 SetImage(STATE_PRESSED, 239 *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_EDIT_PRESSED)); 240 241 // Textfield that overlaps the button. 242 profile_name_textfield_ = new views::Textfield(); 243 profile_name_textfield_->set_controller(controller); 244 profile_name_textfield_->SetFontList(medium_font_list); 245 profile_name_textfield_->SetVisible(false); 246 AddChildView(profile_name_textfield_); 247 } 248 249 views::Textfield* profile_name_textfield() { 250 return profile_name_textfield_; 251 } 252 253 // Hide the editable textfield to show the profile name button instead. 254 void ShowReadOnlyView() { 255 if (profile_name_textfield_) 256 profile_name_textfield_->SetVisible(false); 257 } 258 259 private: 260 // views::ButtonListener: 261 virtual void ButtonPressed(views::Button* sender, 262 const ui::Event& event) OVERRIDE { 263 if (profile_name_textfield_) { 264 profile_name_textfield_->SetVisible(true); 265 profile_name_textfield_->SetText(GetText()); 266 profile_name_textfield_->SelectAll(false); 267 profile_name_textfield_->RequestFocus(); 268 } 269 } 270 271 // views::LabelButton: 272 virtual bool OnKeyReleased(const ui::KeyEvent& event) OVERRIDE { 273 // Override CustomButton's implementation, which presses the button when 274 // you press space and clicks it when you release space, as the space can be 275 // part of the new profile name typed in the textfield. 276 return false; 277 } 278 279 virtual void Layout() OVERRIDE { 280 if (profile_name_textfield_) 281 profile_name_textfield_->SetBounds(0, 0, width(), height()); 282 // This layout trick keeps the text left-aligned and the icon right-aligned. 283 SetHorizontalAlignment(gfx::ALIGN_RIGHT); 284 views::LabelButton::Layout(); 285 label()->SetHorizontalAlignment(gfx::ALIGN_LEFT); 286 } 287 288 // Button that is shown when hovering over the image view. Can be NULL if 289 // the profile name isn't allowed to be edited (e.g. for guest profiles). 290 views::Textfield* profile_name_textfield_; 291 292 DISALLOW_COPY_AND_ASSIGN(EditableProfileName); 293}; 294 295// A title card with one back button right aligned and one label center aligned. 296class TitleCard : public views::View { 297 public: 298 TitleCard(int message_id, views::ButtonListener* listener, 299 views::ImageButton** back_button) { 300 back_button_ = new views::ImageButton(listener); 301 back_button_->SetImageAlignment(views::ImageButton::ALIGN_LEFT, 302 views::ImageButton::ALIGN_MIDDLE); 303 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance(); 304 back_button_->SetImage(views::ImageButton::STATE_NORMAL, 305 rb->GetImageSkiaNamed(IDR_BACK)); 306 back_button_->SetImage(views::ImageButton::STATE_HOVERED, 307 rb->GetImageSkiaNamed(IDR_BACK_H)); 308 back_button_->SetImage(views::ImageButton::STATE_PRESSED, 309 rb->GetImageSkiaNamed(IDR_BACK_P)); 310 back_button_->SetImage(views::ImageButton::STATE_DISABLED, 311 rb->GetImageSkiaNamed(IDR_BACK_D)); 312 *back_button = back_button_; 313 314 title_label_ = new views::Label(l10n_util::GetStringUTF16(message_id)); 315 title_label_->SetHorizontalAlignment(gfx::ALIGN_CENTER); 316 const gfx::FontList& medium_font_list = 317 rb->GetFontList(ui::ResourceBundle::MediumFont); 318 title_label_->SetFontList(medium_font_list); 319 320 AddChildView(back_button_); 321 AddChildView(title_label_); 322 } 323 324 private: 325 virtual void Layout() OVERRIDE{ 326 back_button_->SetBounds( 327 0, 0, back_button_->GetPreferredSize().width(), height()); 328 title_label_->SetBoundsRect(GetContentsBounds()); 329 } 330 331 virtual gfx::Size GetPreferredSize() OVERRIDE{ 332 int height = profiles::kAvatarIconPadding * 2 + 333 std::max(title_label_->GetPreferredSize().height(), 334 back_button_->GetPreferredSize().height()); 335 return gfx::Size(width(), height); 336 } 337 338 views::ImageButton* back_button_; 339 views::Label* title_label_; 340 341 DISALLOW_COPY_AND_ASSIGN(TitleCard); 342}; 343 344// ProfileChooserView --------------------------------------------------------- 345 346// static 347ProfileChooserView* ProfileChooserView::profile_bubble_ = NULL; 348bool ProfileChooserView::close_on_deactivate_for_testing_ = true; 349 350// static 351void ProfileChooserView::ShowBubble( 352 BubbleViewMode view_mode, 353 views::View* anchor_view, 354 views::BubbleBorder::Arrow arrow, 355 views::BubbleBorder::BubbleAlignment border_alignment, 356 const gfx::Rect& anchor_rect, 357 Browser* browser) { 358 profile_bubble_ = new ProfileChooserView(anchor_view, arrow, anchor_rect, 359 browser, view_mode); 360 views::BubbleDelegateView::CreateBubble(profile_bubble_); 361 profile_bubble_->set_close_on_deactivate(close_on_deactivate_for_testing_); 362 profile_bubble_->SetAlignment(border_alignment); 363 profile_bubble_->GetWidget()->Show(); 364 profile_bubble_->SetArrowPaintType(views::BubbleBorder::PAINT_NONE); 365} 366 367// static 368bool ProfileChooserView::IsShowing() { 369 return profile_bubble_ != NULL; 370} 371 372// static 373void ProfileChooserView::Hide() { 374 if (IsShowing()) 375 profile_bubble_->GetWidget()->Close(); 376} 377 378ProfileChooserView::ProfileChooserView(views::View* anchor_view, 379 views::BubbleBorder::Arrow arrow, 380 const gfx::Rect& anchor_rect, 381 Browser* browser, 382 BubbleViewMode view_mode) 383 : BubbleDelegateView(anchor_view, arrow), 384 browser_(browser), 385 view_mode_(view_mode), 386 tutorial_showing_(false) { 387 // Reset the default margins inherited from the BubbleDelegateView. 388 set_margins(gfx::Insets()); 389 390 ResetView(); 391 392 set_background(views::Background::CreateSolidBackground( 393 GetNativeTheme()->GetSystemColor( 394 ui::NativeTheme::kColorId_DialogBackground))); 395 396 avatar_menu_.reset(new AvatarMenu( 397 &g_browser_process->profile_manager()->GetProfileInfoCache(), 398 this, 399 browser_)); 400 avatar_menu_->RebuildMenu(); 401 402 ProfileOAuth2TokenService* oauth2_token_service = 403 ProfileOAuth2TokenServiceFactory::GetForProfile(browser_->profile()); 404 if (oauth2_token_service) 405 oauth2_token_service->AddObserver(this); 406} 407 408ProfileChooserView::~ProfileChooserView() { 409 ProfileOAuth2TokenService* oauth2_token_service = 410 ProfileOAuth2TokenServiceFactory::GetForProfile(browser_->profile()); 411 if (oauth2_token_service) 412 oauth2_token_service->RemoveObserver(this); 413} 414 415void ProfileChooserView::ResetView() { 416 manage_accounts_link_ = NULL; 417 signin_current_profile_link_ = NULL; 418 users_button_ = NULL; 419 lock_button_ = NULL; 420 add_account_button_ = NULL; 421 current_profile_photo_ = NULL; 422 current_profile_name_ = NULL; 423 tutorial_ok_button_ = NULL; 424 tutorial_learn_more_link_ = NULL; 425 tutorial_enable_new_profile_management_button_ = NULL; 426 account_removal_cancel_button_ = NULL; 427 gaia_signin_cancel_button_ = NULL; 428 open_other_profile_indexes_map_.clear(); 429 current_profile_accounts_map_.clear(); 430 tutorial_showing_ = false; 431} 432 433void ProfileChooserView::Init() { 434 ShowView(view_mode_, avatar_menu_.get()); 435} 436 437void ProfileChooserView::OnAvatarMenuChanged( 438 AvatarMenu* avatar_menu) { 439 // Refresh the view with the new menu. We can't just update the local copy 440 // as this may have been triggered by a sign out action, in which case 441 // the view is being destroyed. 442 ShowView(BUBBLE_VIEW_MODE_PROFILE_CHOOSER, avatar_menu); 443} 444 445void ProfileChooserView::OnRefreshTokenAvailable( 446 const std::string& account_id) { 447 // Refresh the account management view when a new account is added to the 448 // profile. 449 if (view_mode_ == BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT || 450 view_mode_ == BUBBLE_VIEW_MODE_GAIA_SIGNIN || 451 view_mode_ == BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT) { 452 ShowView(BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT, avatar_menu_.get()); 453 } 454} 455 456void ProfileChooserView::OnRefreshTokenRevoked(const std::string& account_id) { 457 // Refresh the account management view when an account is removed from the 458 // profile. 459 if (view_mode_ == BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT) 460 ShowView(BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT, avatar_menu_.get()); 461} 462 463void ProfileChooserView::ShowView(BubbleViewMode view_to_display, 464 AvatarMenu* avatar_menu) { 465 // The account management view should only be displayed if the active profile 466 // is signed in. 467 if (view_to_display == BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT) { 468 const AvatarMenu::Item& active_item = avatar_menu->GetItemAt( 469 avatar_menu->GetActiveProfileIndex()); 470 DCHECK(active_item.signed_in); 471 } 472 473 // Records if the "mirror enabled" tutorial card is currently shown before 474 // resetting the view. 475 bool tutorial_shown = tutorial_showing_; 476 ResetView(); 477 RemoveAllChildViews(true); 478 view_mode_ = view_to_display; 479 480 views::GridLayout* layout; 481 views::View* sub_view; 482 switch (view_mode_) { 483 case BUBBLE_VIEW_MODE_GAIA_SIGNIN: 484 case BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT: 485 layout = CreateSingleColumnLayout(this, kFixedGaiaViewWidth); 486 sub_view = CreateGaiaSigninView( 487 view_mode_ == BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT); 488 break; 489 case BUBBLE_VIEW_MODE_ACCOUNT_REMOVAL: 490 layout = CreateSingleColumnLayout(this, kFixedAccountRemovalViewWidth); 491 sub_view = CreateAccountRemovalView(); 492 break; 493 default: 494 layout = CreateSingleColumnLayout(this, kFixedMenuWidth); 495 sub_view = CreateProfileChooserView(avatar_menu, tutorial_shown); 496 } 497 layout->StartRow(1, 0); 498 layout->AddView(sub_view); 499 Layout(); 500 if (GetBubbleFrameView()) 501 SizeToContents(); 502} 503 504void ProfileChooserView::WindowClosing() { 505 DCHECK_EQ(profile_bubble_, this); 506 profile_bubble_ = NULL; 507} 508 509void ProfileChooserView::ButtonPressed(views::Button* sender, 510 const ui::Event& event) { 511 // Disable button after clicking so that it doesn't get clicked twice and 512 // start a second action... which can crash Chrome. But don't disable if it 513 // has no parent (like in tests) because that will also crash. 514 if (sender->parent()) 515 sender->SetEnabled(false); 516 517 if (sender == users_button_) { 518 profiles::ShowUserManagerMaybeWithTutorial(browser_->profile()); 519 } else if (sender == lock_button_) { 520 profiles::LockProfile(browser_->profile()); 521 } else if (sender == add_account_button_) { 522 ShowView(BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT, avatar_menu_.get()); 523 } else if (sender == tutorial_ok_button_) { 524 // If the user manually dismissed the tutorial, never show it again by 525 // setting the number of times shown to the maximum plus 1, so that later we 526 // could distinguish between the dismiss case and the case when the tutorial 527 // is indeed shown for the maximum number of times. 528 browser_->profile()->GetPrefs()->SetInteger( 529 prefs::kProfileAvatarTutorialShown, kProfileAvatarTutorialShowMax + 1); 530 ShowView(BUBBLE_VIEW_MODE_PROFILE_CHOOSER, avatar_menu_.get()); 531 } else if (sender == tutorial_enable_new_profile_management_button_) { 532 EnableNewProfileManagementPreview(); 533 } else if (sender == remove_account_and_relaunch_button_) { 534 RemoveAccount(); 535 } else if (sender == account_removal_cancel_button_) { 536 account_id_to_remove_.clear(); 537 ShowView(BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT, avatar_menu_.get()); 538 } else if (sender == gaia_signin_cancel_button_) { 539 std::string primary_account = 540 SigninManagerFactory::GetForProfile(browser_->profile())-> 541 GetAuthenticatedUsername(); 542 ShowView(primary_account.empty() ? BUBBLE_VIEW_MODE_PROFILE_CHOOSER : 543 BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT, 544 avatar_menu_.get()); 545 } else if (current_profile_photo_ && 546 sender == current_profile_photo_->change_photo_button()) { 547 avatar_menu_->EditProfile(avatar_menu_->GetActiveProfileIndex()); 548 } else { 549 // One of the "other profiles" buttons was pressed. 550 ButtonIndexes::const_iterator match = 551 open_other_profile_indexes_map_.find(sender); 552 DCHECK(match != open_other_profile_indexes_map_.end()); 553 avatar_menu_->SwitchToProfile( 554 match->second, 555 ui::DispositionFromEventFlags(event.flags()) == NEW_WINDOW, 556 ProfileMetrics::SWITCH_PROFILE_ICON); 557 } 558} 559 560void ProfileChooserView::OnMenuButtonClicked(views::View* source, 561 const gfx::Point& point) { 562 AccountButtonIndexes::const_iterator match = 563 current_profile_accounts_map_.find(source); 564 DCHECK(match != current_profile_accounts_map_.end()); 565 account_id_to_remove_ = match->second; 566 ShowView(BUBBLE_VIEW_MODE_ACCOUNT_REMOVAL, avatar_menu_.get()); 567} 568 569void ProfileChooserView::RemoveAccount() { 570 DCHECK(!account_id_to_remove_.empty()); 571 MutableProfileOAuth2TokenService* oauth2_token_service = 572 ProfileOAuth2TokenServiceFactory::GetPlatformSpecificForProfile( 573 browser_->profile()); 574 if (oauth2_token_service) 575 oauth2_token_service->RevokeCredentials(account_id_to_remove_); 576 account_id_to_remove_.clear(); 577 578 chrome::AttemptRestart(); 579} 580 581void ProfileChooserView::LinkClicked(views::Link* sender, int event_flags) { 582 if (sender == manage_accounts_link_) { 583 // ShowView() will DCHECK if this view is displayed for non signed-in users. 584 ShowView(BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT, avatar_menu_.get()); 585 } else if (sender == tutorial_learn_more_link_) { 586 // TODO(guohui): update |learn_more_url| once it is decided. 587 const GURL lear_more_url("https://support.google.com/chrome/?hl=en#to"); 588 chrome::NavigateParams params( 589 browser_->profile(), 590 lear_more_url, 591 content::PAGE_TRANSITION_LINK); 592 params.disposition = NEW_FOREGROUND_TAB; 593 chrome::Navigate(¶ms); 594 } else { 595 DCHECK(sender == signin_current_profile_link_); 596 ShowView(BUBBLE_VIEW_MODE_GAIA_SIGNIN, avatar_menu_.get()); 597 } 598} 599 600void ProfileChooserView::StyledLabelLinkClicked( 601 const gfx::Range& range, int event_flags) { 602 chrome::ShowSettings(browser_); 603} 604 605bool ProfileChooserView::HandleKeyEvent(views::Textfield* sender, 606 const ui::KeyEvent& key_event) { 607 views::Textfield* name_textfield = 608 current_profile_name_->profile_name_textfield(); 609 DCHECK(sender == name_textfield); 610 611 if (key_event.key_code() == ui::VKEY_RETURN || 612 key_event.key_code() == ui::VKEY_TAB) { 613 // Pressing Tab/Enter commits the new profile name, unless it's empty. 614 base::string16 new_profile_name = name_textfield->text(); 615 if (new_profile_name.empty()) 616 return true; 617 618 const AvatarMenu::Item& active_item = avatar_menu_->GetItemAt( 619 avatar_menu_->GetActiveProfileIndex()); 620 Profile* profile = g_browser_process->profile_manager()->GetProfile( 621 active_item.profile_path); 622 DCHECK(profile); 623 624 if (profile->IsManaged()) 625 return true; 626 627 profiles::UpdateProfileName(profile, new_profile_name); 628 current_profile_name_->ShowReadOnlyView(); 629 return true; 630 } 631 return false; 632} 633 634views::View* ProfileChooserView::CreateProfileChooserView( 635 AvatarMenu* avatar_menu, bool tutorial_shown) { 636 // TODO(guohui, noms): the view should be customized based on whether new 637 // profile management preview is enabled or not. 638 639 views::View* view = new views::View(); 640 views::GridLayout* layout = CreateSingleColumnLayout(view, kFixedMenuWidth); 641 // Separate items into active and alternatives. 642 Indexes other_profiles; 643 views::View* tutorial_view = NULL; 644 views::View* current_profile_view = NULL; 645 views::View* current_profile_accounts = NULL; 646 views::View* option_buttons_view = NULL; 647 for (size_t i = 0; i < avatar_menu->GetNumberOfItems(); ++i) { 648 const AvatarMenu::Item& item = avatar_menu->GetItemAt(i); 649 if (item.active) { 650 option_buttons_view = CreateOptionsView(item.signed_in); 651 if (view_mode_ == BUBBLE_VIEW_MODE_PROFILE_CHOOSER) { 652 tutorial_view = switches::IsNewProfileManagement() ? 653 CreatePreviewEnabledTutorialView(item, tutorial_shown) : 654 CreateNewProfileManagementPreviewView(); 655 current_profile_view = CreateCurrentProfileView(item, false); 656 } else { 657 current_profile_view = CreateCurrentProfileEditableView(item); 658 current_profile_accounts = CreateCurrentProfileAccountsView(item); 659 } 660 } else { 661 other_profiles.push_back(i); 662 } 663 } 664 665 if (tutorial_view) { 666 layout->StartRow(1, 0); 667 layout->AddView(tutorial_view); 668 } 669 670 if (!current_profile_view) { 671 // Guest windows don't have an active profile. 672 current_profile_view = CreateGuestProfileView(); 673 option_buttons_view = CreateOptionsView(false); 674 } 675 676 layout->StartRow(1, 0); 677 layout->AddView(current_profile_view); 678 679 if (view_mode_ == BUBBLE_VIEW_MODE_PROFILE_CHOOSER) { 680 layout->StartRow(1, 0); 681 if (switches::IsFastUserSwitching()) 682 layout->AddView(CreateOtherProfilesView(other_profiles)); 683 } else { 684 DCHECK(current_profile_accounts); 685 layout->StartRow(0, 0); 686 layout->AddView(new views::Separator(views::Separator::HORIZONTAL)); 687 layout->StartRow(1, 0); 688 layout->AddView(current_profile_accounts); 689 } 690 691 layout->StartRow(0, 0); 692 layout->AddView(new views::Separator(views::Separator::HORIZONTAL)); 693 694 // Action buttons. 695 layout->StartRow(0, 0); 696 layout->AddView(option_buttons_view); 697 698 return view; 699} 700 701views::View* ProfileChooserView::CreatePreviewEnabledTutorialView( 702 const AvatarMenu::Item& current_avatar_item, 703 bool tutorial_shown) { 704 if (!switches::IsNewProfileManagementPreviewEnabled()) 705 return NULL; 706 707 Profile* profile = browser_->profile(); 708 const int show_count = profile->GetPrefs()->GetInteger( 709 prefs::kProfileAvatarTutorialShown); 710 // Do not show the tutorial if user has dismissed it. 711 if (show_count > kProfileAvatarTutorialShowMax) 712 return NULL; 713 714 if (!tutorial_shown) { 715 if (show_count == kProfileAvatarTutorialShowMax) 716 return NULL; 717 profile->GetPrefs()->SetInteger( 718 prefs::kProfileAvatarTutorialShown, show_count + 1); 719 } 720 tutorial_showing_ = true; 721 722 return CreateTutorialView( 723 l10n_util::GetStringUTF16(IDS_PROFILES_PREVIEW_ENABLED_TUTORIAL_TITLE), 724 l10n_util::GetStringUTF16( 725 IDS_PROFILES_PREVIEW_ENABLED_TUTORIAL_CONTENT_TEXT), 726 l10n_util::GetStringUTF16(IDS_PROFILES_PROFILE_TUTORIAL_LEARN_MORE), 727 l10n_util::GetStringUTF16(IDS_PROFILES_TUTORIAL_OK_BUTTON), 728 &tutorial_learn_more_link_, 729 &tutorial_ok_button_); 730} 731 732views::View* ProfileChooserView::CreateTutorialView( 733 const base::string16& title_text, 734 const base::string16& content_text, 735 const base::string16& link_text, 736 const base::string16& button_text, 737 views::Link** link, 738 views::LabelButton** button) { 739 views::View* view = new views::View(); 740 view->set_background(views::Background::CreateSolidBackground( 741 profiles::kAvatarTutorialBackgroundColor)); 742 views::GridLayout* layout = CreateSingleColumnLayout(view, 743 kFixedMenuWidth - 2 * views::kButtonHEdgeMarginNew); 744 layout->SetInsets(views::kButtonVEdgeMarginNew, 745 views::kButtonHEdgeMarginNew, 746 views::kButtonVEdgeMarginNew, 747 views::kButtonHEdgeMarginNew); 748 749 // Adds title. 750 views::Label* title_label = new views::Label(title_text); 751 title_label->SetHorizontalAlignment(gfx::ALIGN_LEFT); 752 title_label->SetAutoColorReadabilityEnabled(false); 753 title_label->SetEnabledColor(SK_ColorWHITE); 754 title_label ->SetFontList(ui::ResourceBundle::GetSharedInstance().GetFontList( 755 ui::ResourceBundle::MediumFont)); 756 layout->StartRow(1, 0); 757 layout->AddView(title_label); 758 759 // Adds body content. 760 views::Label* content_label = new views::Label(content_text); 761 content_label->SetMultiLine(true); 762 content_label->SetHorizontalAlignment(gfx::ALIGN_LEFT); 763 content_label->SetAutoColorReadabilityEnabled(false); 764 content_label->SetEnabledColor(profiles::kAvatarTutorialContentTextColor); 765 layout->StartRowWithPadding(1, 0, 0, views::kRelatedControlVerticalSpacing); 766 layout->AddView(content_label); 767 768 // Adds links and buttons. 769 views::View* button_row = new views::View(); 770 views::GridLayout* button_layout = new views::GridLayout(button_row); 771 views::ColumnSet* button_columns = button_layout->AddColumnSet(0); 772 button_columns->AddColumn(views::GridLayout::LEADING, 773 views::GridLayout::CENTER, 0, views::GridLayout::USE_PREF, 0, 0); 774 button_columns->AddPaddingColumn( 775 1, views::kUnrelatedControlHorizontalSpacing); 776 button_columns->AddColumn(views::GridLayout::TRAILING, 777 views::GridLayout::CENTER, 0, views::GridLayout::USE_PREF, 0, 0); 778 button_row->SetLayoutManager(button_layout); 779 780 *link = CreateLink(link_text, this); 781 (*link)->SetHorizontalAlignment(gfx::ALIGN_LEFT); 782 (*link)->SetAutoColorReadabilityEnabled(false); 783 (*link)->SetEnabledColor(SK_ColorWHITE); 784 button_layout->StartRow(1, 0); 785 button_layout->AddView(*link); 786 787 *button = new views::LabelButton(this, button_text); 788 (*button)->SetHorizontalAlignment(gfx::ALIGN_CENTER); 789 (*button)->SetStyle(views::Button::STYLE_BUTTON); 790 button_layout->AddView(*button); 791 792 layout->StartRowWithPadding(1, 0, 0, views::kUnrelatedControlVerticalSpacing); 793 layout->AddView(button_row); 794 795 // Adds a padded caret image at the bottom. 796 views::View* padded_caret_view = new views::View(); 797 views::GridLayout* padded_caret_layout = 798 new views::GridLayout(padded_caret_view); 799 views::ColumnSet* padded_columns = padded_caret_layout->AddColumnSet(0); 800 padded_columns->AddPaddingColumn(0, views::kButtonHEdgeMarginNew); 801 padded_columns->AddColumn(views::GridLayout::LEADING, 802 views::GridLayout::CENTER, 0, views::GridLayout::USE_PREF, 0, 0); 803 padded_caret_view->SetLayoutManager(padded_caret_layout); 804 805 views::ImageView* caret_image_view = new views::ImageView(); 806 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance(); 807 caret_image_view->SetImage( 808 *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_CARET)); 809 810 padded_caret_layout->StartRow(1, 0); 811 padded_caret_layout->AddView(caret_image_view); 812 813 views::View* view_with_caret = new views::View(); 814 views::GridLayout* layout_with_caret = 815 CreateSingleColumnLayout(view_with_caret, kFixedMenuWidth); 816 layout_with_caret->StartRow(1, 0); 817 layout_with_caret->AddView(view); 818 layout_with_caret->StartRow(1, 0); 819 layout_with_caret->AddView(padded_caret_view); 820 return view_with_caret; 821} 822 823views::View* ProfileChooserView::CreateCurrentProfileView( 824 const AvatarMenu::Item& avatar_item, 825 bool is_guest) { 826 views::View* view = new views::View(); 827 views::GridLayout* layout = CreateDoubleColumnLayout(view); 828 layout->SetInsets(views::kButtonVEdgeMarginNew, 829 views::kButtonHEdgeMarginNew, 830 views::kButtonVEdgeMarginNew, 831 views::kButtonHEdgeMarginNew); 832 833 current_profile_photo_ = 834 new EditableProfilePhoto(this, avatar_item.icon, !is_guest); 835 view->SetBoundsRect(current_profile_photo_->bounds()); 836 current_profile_name_ = new EditableProfileName( 837 this, profiles::GetAvatarNameForProfile(browser_->profile()), !is_guest); 838 layout->StartRow(1, 0); 839 layout->AddView(current_profile_photo_, 1, 3); 840 layout->AddView(current_profile_name_); 841 842 if (is_guest) { 843 layout->StartRow(1, 0); 844 layout->SkipColumns(1); 845 layout->StartRow(1, 0); 846 layout->SkipColumns(1); 847 } else if (avatar_item.signed_in) { 848 manage_accounts_link_ = CreateLink( 849 l10n_util::GetStringUTF16(IDS_PROFILES_PROFILE_MANAGE_ACCOUNTS_BUTTON), 850 this); 851 layout->StartRow(1, 0); 852 layout->SkipColumns(1); 853 layout->AddView(manage_accounts_link_); 854 layout->StartRow(1, 0); 855 layout->SkipColumns(1); 856 } else { 857 signin_current_profile_link_ = CreateLink( 858 l10n_util::GetStringFUTF16( 859 IDS_SYNC_START_SYNC_BUTTON_LABEL, 860 l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME)), 861 this); 862 layout->StartRow(1, 0); 863 layout->SkipColumns(1); 864 layout->AddView(signin_current_profile_link_); 865 layout->StartRow(1, 0); 866 layout->SkipColumns(1); 867 } 868 869 return view; 870} 871 872views::View* ProfileChooserView::CreateCurrentProfileEditableView( 873 const AvatarMenu::Item& avatar_item) { 874 DCHECK(avatar_item.signed_in); 875 views::View* view = new views::View(); 876 views::GridLayout* layout = CreateDoubleColumnLayout(view); 877 layout->SetInsets(views::kButtonVEdgeMarginNew, 878 views::kButtonHEdgeMarginNew, 879 views::kButtonVEdgeMarginNew, 880 views::kButtonHEdgeMarginNew); 881 882 current_profile_photo_ = 883 new EditableProfilePhoto(this, avatar_item.icon, true); 884 view->SetBoundsRect(current_profile_photo_->bounds()); 885 current_profile_name_ = new EditableProfileName( 886 this, profiles::GetAvatarNameForProfile(browser_->profile()), true); 887 888 layout->StartRow(1, 0); 889 layout->AddView(current_profile_photo_, 1, 3); 890 layout->AddView(current_profile_name_); 891 892 layout->StartRow(1, 0); 893 layout->SkipColumns(1); 894 895 layout->StartRow(1, 0); 896 layout->SkipColumns(1); 897 return view; 898} 899 900views::View* ProfileChooserView::CreateGuestProfileView() { 901 gfx::Image guest_icon = 902 ui::ResourceBundle::GetSharedInstance().GetImageNamed(IDR_LOGIN_GUEST); 903 AvatarMenu::Item guest_avatar_item(0, 0, guest_icon); 904 guest_avatar_item.active = true; 905 guest_avatar_item.name = l10n_util::GetStringUTF16( 906 IDS_PROFILES_GUEST_PROFILE_NAME); 907 guest_avatar_item.signed_in = false; 908 909 return CreateCurrentProfileView(guest_avatar_item, true); 910} 911 912views::View* ProfileChooserView::CreateOtherProfilesView( 913 const Indexes& avatars_to_show) { 914 views::View* view = new views::View(); 915 views::GridLayout* layout = CreateSingleColumnLayout( 916 view, kFixedMenuWidth - 2 * views::kButtonHEdgeMarginNew); 917 layout->SetInsets(0, views::kButtonHEdgeMarginNew, 918 views::kButtonVEdgeMarginNew, views::kButtonHEdgeMarginNew); 919 int num_avatars_to_show = avatars_to_show.size(); 920 for (int i = 0; i < num_avatars_to_show; ++i) { 921 const size_t index = avatars_to_show[i]; 922 const AvatarMenu::Item& item = avatar_menu_->GetItemAt(index); 923 const int kSmallImageSide = 32; 924 925 gfx::Image image = profiles::GetSizedAvatarIconWithBorder( 926 item.icon, true, 927 kSmallImageSide + profiles::kAvatarIconPadding, 928 kSmallImageSide + profiles::kAvatarIconPadding); 929 930 views::LabelButton* button = new views::LabelButton(this, item.name); 931 open_other_profile_indexes_map_[button] = index; 932 button->SetImage(views::Button::STATE_NORMAL, *image.ToImageSkia()); 933 button->SetFontList(ui::ResourceBundle::GetSharedInstance().GetFontList( 934 ui::ResourceBundle::MediumFont)); 935 button->SetBorder(views::Border::NullBorder()); 936 937 layout->StartRow(1, 0); 938 layout->AddView(button); 939 940 // The last avatar in the list does not need any bottom padding. 941 if (i < num_avatars_to_show - 1) 942 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); 943 } 944 945 return view; 946} 947 948views::View* ProfileChooserView::CreateOptionsView(bool enable_lock) { 949 views::View* view = new views::View(); 950 views::GridLayout* layout; 951 952 // Only signed-in users have the ability to lock. 953 if (enable_lock) { 954 layout = new views::GridLayout(view); 955 views::ColumnSet* columns = layout->AddColumnSet(0); 956 int width_of_lock_button = 957 2 * views::kUnrelatedControlLargeHorizontalSpacing + 12; 958 int width_of_users_button = kFixedMenuWidth - width_of_lock_button; 959 columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 0, 960 views::GridLayout::FIXED, width_of_users_button, 961 width_of_users_button); 962 columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 0, 963 views::GridLayout::FIXED, width_of_lock_button, 964 width_of_lock_button); 965 view->SetLayoutManager(layout); 966 } else { 967 layout = CreateSingleColumnLayout(view, kFixedMenuWidth); 968 } 969 970 // The horizontal padding will be set by each button individually, so that 971 // in the hovered state the button spans the entire parent view. 972 layout->SetInsets(views::kRelatedControlVerticalSpacing, 0, 973 views::kRelatedControlVerticalSpacing, 0); 974 975 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance(); 976 users_button_ = new BackgroundColorHoverButton( 977 this, 978 l10n_util::GetStringFUTF16(IDS_PROFILES_NOT_YOU_BUTTON, 979 profiles::GetAvatarNameForProfile(browser_->profile())), 980 *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_AVATAR), 981 *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_AVATAR)); 982 983 layout->StartRow(1, 0); 984 layout->AddView(users_button_); 985 986 if (enable_lock) { 987 lock_button_ = new BackgroundColorHoverButton( 988 this, 989 base::string16(), 990 *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_LOCK), 991 *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_LOCK)); 992 layout->AddView(lock_button_); 993 } 994 return view; 995} 996 997views::View* ProfileChooserView::CreateCurrentProfileAccountsView( 998 const AvatarMenu::Item& avatar_item) { 999 DCHECK(avatar_item.signed_in); 1000 views::View* view = new views::View(); 1001 int column_width = kFixedMenuWidth - 2 * views::kButtonHEdgeMarginNew; 1002 views::GridLayout* layout = CreateSingleColumnLayout(view, column_width); 1003 layout->SetInsets(views::kButtonVEdgeMarginNew, 1004 views::kButtonHEdgeMarginNew, 1005 views::kButtonVEdgeMarginNew, 1006 views::kButtonHEdgeMarginNew); 1007 1008 Profile* profile = browser_->profile(); 1009 std::string primary_account = 1010 SigninManagerFactory::GetForProfile(profile)->GetAuthenticatedUsername(); 1011 DCHECK(!primary_account.empty()); 1012 std::vector<std::string>accounts = 1013 profiles::GetSecondaryAccountsForProfile(profile, primary_account); 1014 1015 // The primary account should always be listed first. 1016 // TODO(rogerta): we still need to further differentiate the primary account 1017 // from the others in the UI, so more work is likely required here: 1018 // crbug.com/311124. 1019 CreateAccountButton(layout, primary_account, true, column_width); 1020 for (size_t i = 0; i < accounts.size(); ++i) 1021 CreateAccountButton(layout, accounts[i], false, column_width); 1022 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); 1023 1024 add_account_button_ = new views::BlueButton( 1025 this, 1026 l10n_util::GetStringFUTF16(IDS_PROFILES_PROFILE_ADD_ACCOUNT_BUTTON, 1027 avatar_item.name)); 1028 layout->StartRow(1, 0); 1029 layout->AddView(add_account_button_); 1030 return view; 1031} 1032 1033void ProfileChooserView::CreateAccountButton(views::GridLayout* layout, 1034 const std::string& account, 1035 bool is_primary_account, 1036 int width) { 1037 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance(); 1038 const gfx::ImageSkia* menu_marker = 1039 rb->GetImageNamed(IDR_CLOSE_1).ToImageSkia(); 1040 // Use a MenuButtonListener and not a regular ButtonListener to be 1041 // able to distinguish between the unnamed "other profile" buttons and the 1042 // unnamed "multiple accounts" buttons. 1043 views::MenuButton* email_button = new views::MenuButton( 1044 NULL, 1045 gfx::ElideEmail(base::UTF8ToUTF16(account), 1046 rb->GetFontList(ui::ResourceBundle::BaseFont), 1047 width - menu_marker->width()), 1048 this, 1049 true /* show_menu_marker */); 1050 email_button->SetBorder(views::Border::CreateEmptyBorder(0, 0, 0, 0)); 1051 email_button->set_menu_marker(menu_marker); 1052 if (!is_primary_account) 1053 layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); 1054 layout->StartRow(1, 0); 1055 layout->AddView(email_button); 1056 1057 // Save the original email address, as the button text could be elided. 1058 current_profile_accounts_map_[email_button] = account; 1059} 1060 1061views::View* ProfileChooserView::CreateGaiaSigninView( 1062 bool add_secondary_account) { 1063 views::View* view = new views::View(); 1064 views::GridLayout* layout = 1065 CreateSingleColumnLayout(view, kFixedGaiaViewWidth); 1066 1067 // Adds title. 1068 views::View* padded_title = new views::View(); 1069 int available_width = kFixedGaiaViewWidth - 2 * views::kButtonHEdgeMarginNew; 1070 views::GridLayout* padded_layout = CreateSingleColumnLayout( 1071 padded_title, available_width); 1072 padded_layout->SetInsets(views::kButtonVEdgeMarginNew, 1073 views::kButtonHEdgeMarginNew, 1074 views::kButtonVEdgeMarginNew, 1075 views::kButtonHEdgeMarginNew); 1076 padded_layout->StartRow(1, 0); 1077 padded_layout->AddView(new TitleCard( 1078 add_secondary_account ? IDS_PROFILES_GAIA_ADD_ACCOUNT_TITLE : 1079 IDS_PROFILES_GAIA_SIGNIN_TITLE, 1080 this, &gaia_signin_cancel_button_)); 1081 1082 layout->StartRow(1, 0); 1083 layout->AddView(padded_title); 1084 layout->StartRow(1, 0); 1085 layout->AddView(new views::Separator(views::Separator::HORIZONTAL)); 1086 1087 // Adds Gaia signin webview 1088 Profile* profile = browser_->profile(); 1089 views::WebView* web_view = new views::WebView(profile); 1090 signin::Source source = add_secondary_account ? 1091 signin::SOURCE_AVATAR_BUBBLE_ADD_ACCOUNT : 1092 signin::SOURCE_AVATAR_BUBBLE_SIGN_IN; 1093 GURL url(signin::GetPromoURL( 1094 source, false /* auto_close */, true /* is_constrained */)); 1095 web_view->LoadInitialURL(url); 1096 web_view->SetPreferredSize( 1097 gfx::Size(kFixedGaiaViewWidth, kFixedGaiaViewHeight)); 1098 1099 layout->StartRow(1, 0); 1100 layout->AddView(web_view); 1101 1102 return view; 1103} 1104 1105views::View* ProfileChooserView::CreateAccountRemovalView() { 1106 views::View* view = new views::View(); 1107 views::GridLayout* layout = CreateSingleColumnLayout( 1108 view, kFixedAccountRemovalViewWidth - 2 * views::kButtonHEdgeMarginNew); 1109 layout->SetInsets(views::kButtonVEdgeMarginNew, 1110 views::kButtonHEdgeMarginNew, 1111 views::kButtonVEdgeMarginNew, 1112 views::kButtonHEdgeMarginNew); 1113 1114 // Adds title. 1115 layout->StartRow(1, 0); 1116 layout->AddView(new TitleCard(IDS_PROFILES_ACCOUNT_REMOVAL_TITLE, this, 1117 &account_removal_cancel_button_)); 1118 layout->StartRowWithPadding(1, 0, 0, views::kRelatedControlVerticalSpacing); 1119 layout->AddView(new views::Separator(views::Separator::HORIZONTAL)); 1120 1121 const std::string& primary_account = SigninManagerFactory::GetForProfile( 1122 browser_->profile())->GetAuthenticatedUsername(); 1123 bool is_primary_account = primary_account == account_id_to_remove_; 1124 1125 // Adds main text. 1126 layout->StartRowWithPadding(1, 0, 0, views::kUnrelatedControlVerticalSpacing); 1127 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance(); 1128 const gfx::FontList& small_font_list = 1129 rb->GetFontList(ui::ResourceBundle::SmallFont); 1130 1131 if (is_primary_account) { 1132 std::vector<size_t> offsets; 1133 const base::string16 settings_text = 1134 l10n_util::GetStringUTF16(IDS_PROFILES_SETTINGS_LINK); 1135 const base::string16 primmary_account_removal_text = 1136 l10n_util::GetStringFUTF16(IDS_PROFILES_PRIMARY_ACCOUNT_REMOVAL_TEXT, 1137 base::UTF8ToUTF16(account_id_to_remove_), settings_text, &offsets); 1138 views::StyledLabel* primary_account_removal_label = 1139 new views::StyledLabel(primmary_account_removal_text, this); 1140 primary_account_removal_label->AddStyleRange( 1141 gfx::Range(offsets[1], offsets[1] + settings_text.size()), 1142 views::StyledLabel::RangeStyleInfo::CreateForLink()); 1143 primary_account_removal_label->SetBaseFontList(small_font_list); 1144 layout->AddView(primary_account_removal_label); 1145 } else { 1146 views::Label* content_label = new views::Label( 1147 l10n_util::GetStringUTF16(IDS_PROFILES_ACCOUNT_REMOVAL_TEXT)); 1148 content_label->SetMultiLine(true); 1149 content_label->SetHorizontalAlignment(gfx::ALIGN_LEFT); 1150 content_label->SetFontList(small_font_list); 1151 layout->AddView(content_label); 1152 } 1153 1154 // Adds button. 1155 if (!is_primary_account) { 1156 remove_account_and_relaunch_button_ = new views::BlueButton( 1157 this, l10n_util::GetStringUTF16(IDS_PROFILES_ACCOUNT_REMOVAL_BUTTON)); 1158 remove_account_and_relaunch_button_->SetHorizontalAlignment( 1159 gfx::ALIGN_CENTER); 1160 layout->StartRowWithPadding( 1161 1, 0, 0, views::kUnrelatedControlVerticalSpacing); 1162 layout->AddView(remove_account_and_relaunch_button_); 1163 } else { 1164 layout->AddPaddingRow(0, views::kUnrelatedControlVerticalSpacing); 1165 } 1166 1167 return view; 1168} 1169 1170views::View* ProfileChooserView::CreateNewProfileManagementPreviewView() { 1171 return CreateTutorialView( 1172 l10n_util::GetStringUTF16(IDS_PROFILES_PREVIEW_TUTORIAL_TITLE), 1173 l10n_util::GetStringUTF16(IDS_PROFILES_PREVIEW_TUTORIAL_CONTENT_TEXT), 1174 l10n_util::GetStringUTF16(IDS_PROFILES_PROFILE_TUTORIAL_LEARN_MORE), 1175 l10n_util::GetStringUTF16(IDS_PROFILES_TUTORIAL_TRY_BUTTON), 1176 &tutorial_learn_more_link_, 1177 &tutorial_enable_new_profile_management_button_); 1178} 1179 1180void ProfileChooserView::EnableNewProfileManagementPreview() { 1181 const char kNewProfileManagementExperimentInternalName[] = 1182 "enable-new-profile-management"; 1183 about_flags::PrefServiceFlagsStorage flags_storage( 1184 g_browser_process->local_state()); 1185 about_flags::SetExperimentEnabled( 1186 &flags_storage, 1187 kNewProfileManagementExperimentInternalName, 1188 true); 1189 1190 CommandLine::ForCurrentProcess()->AppendSwitch( 1191 switches::kNewProfileManagement); 1192 chrome::ShowUserManagerWithTutorial(profiles::USER_MANAGER_TUTORIAL_OVERVIEW); 1193} 1194