profile_chooser_view.cc revision 6d86b77056ed63eb6871182f42a9fd5f07550f90
1a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch// Copyright 2014 The Chromium Authors. All rights reserved.
2c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// found in the LICENSE file.
4c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
5c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/ui/views/profiles/profile_chooser_view.h"
6c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
7c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/prefs/pref_service.h"
8ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "base/strings/utf_string_conversions.h"
9010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "chrome/browser/browser_process.h"
10eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "chrome/browser/lifetime/application_lifetime.h"
11a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#include "chrome/browser/profiles/profile_avatar_icon_util.h"
121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "chrome/browser/profiles/profile_info_cache.h"
131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "chrome/browser/profiles/profile_manager.h"
14c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/profiles/profile_metrics.h"
15c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/profiles/profile_window.h"
1603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "chrome/browser/profiles/profiles_state.h"
17a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
18a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#include "chrome/browser/signin/signin_header_helper.h"
19c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/signin/signin_manager_factory.h"
20c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/signin/signin_promo.h"
21c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/ui/browser.h"
22c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/ui/browser_commands.h"
23c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/ui/browser_dialogs.h"
24c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/ui/chrome_pages.h"
25c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/ui/singleton_tabs.h"
26c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/ui/views/profiles/user_manager_view.h"
27c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/common/pref_names.h"
28c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/common/url_constants.h"
29c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "components/signin/core/browser/mutable_profile_oauth2_token_service.h"
30c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "components/signin/core/browser/profile_oauth2_token_service.h"
31c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "components/signin/core/browser/signin_error_controller.h"
32c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "components/signin/core/browser/signin_manager.h"
33c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "components/signin/core/common/profile_management_switches.h"
34868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "grit/chromium_strings.h"
35c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "grit/generated_resources.h"
36c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "grit/theme_resources.h"
37c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "third_party/skia/include/core/SkColor.h"
38c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ui/base/l10n/l10n_util.h"
39c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ui/base/resource/resource_bundle.h"
40c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ui/gfx/canvas.h"
41c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ui/gfx/image/image.h"
42c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ui/gfx/image/image_skia.h"
43c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ui/gfx/path.h"
44c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ui/gfx/skia_util.h"
45010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "ui/gfx/text_elider.h"
46010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "ui/native_theme/native_theme.h"
47010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "ui/views/controls/button/blue_button.h"
48010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "ui/views/controls/button/image_button.h"
49c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ui/views/controls/button/label_button.h"
50c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ui/views/controls/button/menu_button.h"
51c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ui/views/controls/label.h"
52c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ui/views/controls/link.h"
53c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ui/views/controls/separator.h"
54c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ui/views/controls/styled_label.h"
55c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ui/views/controls/textfield/textfield.h"
56010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "ui/views/controls/webview/webview.h"
57010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "ui/views/layout/grid_layout.h"
58010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "ui/views/layout/layout_constants.h"
59010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "ui/views/widget/widget.h"
60c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
61c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace {
62c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
63c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Helpers --------------------------------------------------------------------
64c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
65c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const int kFixedMenuWidth = 250;
66c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const int kButtonHeight = 29;
67c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const int kProfileAvatarTutorialShowMax = 1;
68c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const int kFixedGaiaViewHeight = 400;
69c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const int kFixedGaiaViewWidth = 360;
70c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const int kFixedAccountRemovalViewWidth = 280;
71c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const int kFixedEndPreviewViewWidth = 280;
72868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)const int kLargeImageSide = 88;
73c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
74c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Creates a GridLayout with a single column. This ensures that all the child
75c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// views added get auto-expanded to fill the full width of the bubble.
76c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)views::GridLayout* CreateSingleColumnLayout(views::View* view, int width) {
77c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  views::GridLayout* layout = new views::GridLayout(view);
78c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  view->SetLayoutManager(layout);
79c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
80c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  views::ColumnSet* columns = layout->AddColumnSet(0);
81c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 0,
82c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                     views::GridLayout::FIXED, width, width);
83c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return layout;
84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
85c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
86c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)views::Link* CreateLink(const base::string16& link_text,
87c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                        views::LinkListener* listener) {
88c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  views::Link* link_button = new views::Link(link_text);
89c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  link_button->SetHorizontalAlignment(gfx::ALIGN_LEFT);
90c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  link_button->SetUnderline(false);
91c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  link_button->set_listener(listener);
92c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return link_button;
93c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
94010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
95010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)gfx::ImageSkia CreateSquarePlaceholderImage(int size) {
96010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  SkBitmap bitmap;
97010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  bitmap.setConfig(SkBitmap::kA8_Config, size, size);
98c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  bitmap.allocPixels();
99c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  bitmap.eraseARGB(0, 0, 0, 0);
100c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return gfx::ImageSkia::CreateFrom1xBitmap(bitmap);
101c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
102c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
103c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool HasAuthError(Profile* profile) {
104c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const SigninErrorController* error =
105c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      profiles::GetSigninErrorController(profile);
106c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return error && error->HasError();
107868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
108c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
109c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)std::string GetAuthErrorAccountId(Profile* profile) {
110c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const SigninErrorController* error =
111c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      profiles::GetSigninErrorController(profile);
112c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!error)
113c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return std::string();
114c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
115c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return error->error_account_id();
116c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
117c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
118c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)std::string GetAuthErrorUsername(Profile* profile) {
119c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const SigninErrorController* error =
120c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      profiles::GetSigninErrorController(profile);
121c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!error)
122c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return std::string();
123c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
124c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return error->error_username();
125c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
126c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// BackgroundColorHoverButton -------------------------------------------------
128c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
129c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// A custom button that allows for setting a background color when hovered over.
130c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)class BackgroundColorHoverButton : public views::LabelButton {
131c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) public:
132c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  BackgroundColorHoverButton(views::ButtonListener* listener,
133c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                             const base::string16& text,
134c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                             const gfx::ImageSkia& normal_icon,
135c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                             const gfx::ImageSkia& hover_icon);
136c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  virtual ~BackgroundColorHoverButton();
137c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
138c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) private:
139868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // views::LabelButton:
140c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
141868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
142c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(BackgroundColorHoverButton);
143c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)};
144868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
145c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)BackgroundColorHoverButton::BackgroundColorHoverButton(
146868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    views::ButtonListener* listener,
147010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    const base::string16& text,
148010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    const gfx::ImageSkia& normal_icon,
149010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    const gfx::ImageSkia& hover_icon)
150010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    : views::LabelButton(listener, text) {
151010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  SetBorder(views::Border::CreateEmptyBorder(0, views::kButtonHEdgeMarginNew,
152010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                                             0, views::kButtonHEdgeMarginNew));
153c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  set_min_size(gfx::Size(0, kButtonHeight));
154c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  SetImage(STATE_NORMAL, normal_icon);
155c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  SetImage(STATE_HOVERED, hover_icon);
156c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  SetImage(STATE_PRESSED, hover_icon);
157c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
158868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
159c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)BackgroundColorHoverButton::~BackgroundColorHoverButton() {}
160c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
161c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void BackgroundColorHoverButton::OnPaint(gfx::Canvas* canvas) {
162c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if ((state() == STATE_PRESSED) || (state() == STATE_HOVERED) || HasFocus()) {
163c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    canvas->DrawColor(GetNativeTheme()->GetSystemColor(
164c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        ui::NativeTheme::kColorId_ButtonHoverBackgroundColor));
165c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
166c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  LabelButton::OnPaint(canvas);
167c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
168c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
169c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// SizedContainer -------------------------------------------------
170c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
171c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// A simple container view that takes an explicit preferred size.
172010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)class SizedContainer : public views::View {
173010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) public:
174010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  explicit SizedContainer(const gfx::Size& preferred_size)
175010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      : preferred_size_(preferred_size) {}
176c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
177c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  virtual gfx::Size GetPreferredSize() const OVERRIDE {
178c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return preferred_size_;
179c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
180c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
181c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) private:
182c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  gfx::Size preferred_size_;
183010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)};
184010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
185010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}  // namespace
186010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
187c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
188c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// EditableProfilePhoto -------------------------------------------------
189c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
190c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// A custom Image control that shows a "change" button when moused over.
191c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)class EditableProfilePhoto : public views::ImageView {
192c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) public:
193c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EditableProfilePhoto(views::ButtonListener* listener,
194c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                       const gfx::Image& icon,
195c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                       bool is_editing_allowed,
196c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                       const gfx::Rect& bounds)
197c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      : views::ImageView(),
198868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        change_photo_button_(NULL) {
199c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    gfx::Image image = profiles::GetSizedAvatarIcon(
200c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        icon, true, kLargeImageSide, kLargeImageSide);
201c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    SetImage(image.ToImageSkia());
202c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    SetBoundsRect(bounds);
203c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
204c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Calculate the circular mask that will be used to display the photo.
205c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    circular_mask_.addCircle(SkIntToScalar(bounds.width() / 2),
206c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                             SkIntToScalar(bounds.height() / 2),
207c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                             SkIntToScalar(bounds.width() / 2));
208c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
209c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!is_editing_allowed)
210c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return;
211c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
212c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    set_notify_enter_exit_on_child(true);
213c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
214c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Button overlay that appears when hovering over the image.
215c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    change_photo_button_ = new views::LabelButton(listener, base::string16());
216c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    change_photo_button_->SetHorizontalAlignment(gfx::ALIGN_CENTER);
217868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    change_photo_button_->SetBorder(views::Border::NullBorder());
218c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
219c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const SkColor kBackgroundColor = SkColorSetARGB(65, 255, 255, 255);
220c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    change_photo_button_->set_background(
221c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        views::Background::CreateSolidBackground(kBackgroundColor));
222c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    change_photo_button_->SetImage(views::LabelButton::STATE_NORMAL,
223c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        *ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
224c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            IDR_ICON_PROFILES_EDIT_CAMERA));
225c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
226c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    change_photo_button_->SetSize(bounds.size());
227c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    change_photo_button_->SetVisible(false);
228c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    AddChildView(change_photo_button_);
229c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
230c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
231c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {
232c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Display the profile picture as a circle.
233c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    canvas->ClipPath(circular_mask_, true);
234c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    views::ImageView::OnPaint(canvas);
23558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
23658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
237a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  virtual void PaintChildren(gfx::Canvas* canvas,
238                             const views::CullSet& cull_set) OVERRIDE {
239    // Display any children (the "change photo" overlay) as a circle.
240    canvas->ClipPath(circular_mask_, true);
241    View::PaintChildren(canvas, cull_set);
242  }
243
244  views::LabelButton* change_photo_button() { return change_photo_button_; }
245
246 private:
247  // views::View:
248  virtual void OnMouseEntered(const ui::MouseEvent& event) OVERRIDE {
249    if (change_photo_button_)
250      change_photo_button_->SetVisible(true);
251  }
252
253  virtual void OnMouseExited(const ui::MouseEvent& event) OVERRIDE {
254    if (change_photo_button_)
255      change_photo_button_->SetVisible(false);
256  }
257
258  gfx::Path circular_mask_;
259
260  // Button that is shown when hovering over the image view. Can be NULL if
261  // the photo isn't allowed to be edited (e.g. for guest profiles).
262  views::LabelButton* change_photo_button_;
263
264  DISALLOW_COPY_AND_ASSIGN(EditableProfilePhoto);
265};
266
267
268// EditableProfileName -------------------------------------------------
269
270// A custom text control that turns into a textfield for editing when clicked.
271class EditableProfileName : public views::LabelButton,
272                            public views::ButtonListener {
273 public:
274  EditableProfileName(views::TextfieldController* controller,
275                      const base::string16& text,
276                      bool is_editing_allowed)
277      : views::LabelButton(this, text),
278        profile_name_textfield_(NULL) {
279    ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
280    const gfx::FontList& medium_font_list =
281        rb->GetFontList(ui::ResourceBundle::MediumFont);
282    SetFontList(medium_font_list);
283    SetHorizontalAlignment(gfx::ALIGN_CENTER);
284
285    if (!is_editing_allowed) {
286      SetBorder(views::Border::CreateEmptyBorder(2, 0, 2, 0));
287      return;
288    }
289
290    // Show an "edit" pencil icon when hovering over. In the default state,
291    // we need to create an empty placeholder of the correct size, so that
292    // the text doesn't jump around when the hovered icon appears.
293    gfx::ImageSkia hover_image =
294        *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_EDIT_HOVER);
295    SetImage(STATE_NORMAL, CreateSquarePlaceholderImage(hover_image.width()));
296    SetImage(STATE_HOVERED, hover_image);
297    SetImage(STATE_PRESSED,
298             *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_EDIT_PRESSED));
299    // To center the text, we need to offest it by the width of the icon we
300    // are adding. We need to also add a small top/bottom padding to account
301    // for the textfield's border.
302    SetBorder(views::Border::CreateEmptyBorder(2, hover_image.width(), 2, 0));
303
304    // Textfield that overlaps the button.
305    profile_name_textfield_ = new views::Textfield();
306    profile_name_textfield_->set_controller(controller);
307    profile_name_textfield_->SetFontList(medium_font_list);
308    profile_name_textfield_->SetHorizontalAlignment(gfx::ALIGN_CENTER);
309
310    profile_name_textfield_->SetVisible(false);
311    AddChildView(profile_name_textfield_);
312  }
313
314  views::Textfield* profile_name_textfield() {
315    return profile_name_textfield_;
316  }
317
318  // Hide the editable textfield to show the profile name button instead.
319  void ShowReadOnlyView() {
320    if (profile_name_textfield_)
321      profile_name_textfield_->SetVisible(false);
322  }
323
324 private:
325  // views::ButtonListener:
326  virtual void ButtonPressed(views::Button* sender,
327                            const ui::Event& event) OVERRIDE {
328    if (profile_name_textfield_) {
329      profile_name_textfield_->SetVisible(true);
330      profile_name_textfield_->SetText(GetText());
331      profile_name_textfield_->SelectAll(false);
332      profile_name_textfield_->RequestFocus();
333    }
334  }
335
336  // views::LabelButton:
337  virtual bool OnKeyReleased(const ui::KeyEvent& event) OVERRIDE {
338    // Override CustomButton's implementation, which presses the button when
339    // you press space and clicks it when you release space, as the space can be
340    // part of the new profile name typed in the textfield.
341    return false;
342  }
343
344  virtual void Layout() OVERRIDE {
345    if (profile_name_textfield_)
346      profile_name_textfield_->SetBounds(0, 0, width(), height());
347    // This layout trick keeps the text left-aligned and the icon right-aligned.
348    SetHorizontalAlignment(gfx::ALIGN_RIGHT);
349    views::LabelButton::Layout();
350    label()->SetHorizontalAlignment(gfx::ALIGN_CENTER);
351  }
352
353  // Textfield that is shown when editing the profile name. Can be NULL if
354  // the profile name isn't allowed to be edited (e.g. for guest profiles).
355  views::Textfield* profile_name_textfield_;
356
357  DISALLOW_COPY_AND_ASSIGN(EditableProfileName);
358};
359
360// A title card with one back button right aligned and one label center aligned.
361class TitleCard : public views::View {
362 public:
363  TitleCard(int message_id, views::ButtonListener* listener,
364             views::ImageButton** back_button) {
365    back_button_ = new views::ImageButton(listener);
366    back_button_->SetImageAlignment(views::ImageButton::ALIGN_LEFT,
367                                    views::ImageButton::ALIGN_MIDDLE);
368    ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
369    back_button_->SetImage(views::ImageButton::STATE_NORMAL,
370                           rb->GetImageSkiaNamed(IDR_BACK));
371    back_button_->SetImage(views::ImageButton::STATE_HOVERED,
372                           rb->GetImageSkiaNamed(IDR_BACK_H));
373    back_button_->SetImage(views::ImageButton::STATE_PRESSED,
374                           rb->GetImageSkiaNamed(IDR_BACK_P));
375    back_button_->SetImage(views::ImageButton::STATE_DISABLED,
376                           rb->GetImageSkiaNamed(IDR_BACK_D));
377    *back_button = back_button_;
378
379    title_label_ = new views::Label(l10n_util::GetStringUTF16(message_id));
380    title_label_->SetHorizontalAlignment(gfx::ALIGN_CENTER);
381    const gfx::FontList& medium_font_list =
382        rb->GetFontList(ui::ResourceBundle::MediumFont);
383    title_label_->SetFontList(medium_font_list);
384
385    AddChildView(back_button_);
386    AddChildView(title_label_);
387  }
388
389  // Creates a new view that has the |title_card| with padding at the top, an
390  // edge-to-edge separator below, and the specified |view| at the bottom.
391  static views::View* AddPaddedTitleCard(views::View* view,
392                                         TitleCard* title_card,
393                                         int width) {
394    views::View* titled_view = new views::View();
395    views::GridLayout* layout = new views::GridLayout(titled_view);
396    titled_view->SetLayoutManager(layout);
397
398    // Column set 0 is a single column layout with horizontal padding at left
399    // and right, and column set 1 is a single column layout with no padding.
400    views::ColumnSet* columns = layout->AddColumnSet(0);
401    columns->AddPaddingColumn(1, views::kButtonHEdgeMarginNew);
402    int available_width = width - 2 * views::kButtonHEdgeMarginNew;
403    columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 0,
404        views::GridLayout::FIXED, available_width, available_width);
405    columns->AddPaddingColumn(1, views::kButtonHEdgeMarginNew);
406    layout->AddColumnSet(1)->AddColumn(views::GridLayout::FILL,
407        views::GridLayout::FILL, 0,views::GridLayout::FIXED, width, width);
408
409    layout->StartRowWithPadding(1, 0, 0, views::kButtonVEdgeMarginNew);
410    layout->AddView(title_card);
411    layout->StartRowWithPadding(1, 1, 0, views::kRelatedControlVerticalSpacing);
412    layout->AddView(new views::Separator(views::Separator::HORIZONTAL));
413
414    layout->StartRow(1, 1);
415    layout->AddView(view);
416
417    return titled_view;
418  }
419
420 private:
421  virtual void Layout() OVERRIDE{
422    back_button_->SetBounds(
423        0, 0, back_button_->GetPreferredSize().width(), height());
424    title_label_->SetBoundsRect(GetContentsBounds());
425  }
426
427  virtual gfx::Size GetPreferredSize() const OVERRIDE{
428    int height = std::max(title_label_->GetPreferredSize().height(),
429        back_button_->GetPreferredSize().height());
430    return gfx::Size(width(), height);
431  }
432
433  views::ImageButton* back_button_;
434  views::Label* title_label_;
435
436  DISALLOW_COPY_AND_ASSIGN(TitleCard);
437};
438
439// ProfileChooserView ---------------------------------------------------------
440
441// static
442ProfileChooserView* ProfileChooserView::profile_bubble_ = NULL;
443bool ProfileChooserView::close_on_deactivate_for_testing_ = true;
444
445// static
446void ProfileChooserView::ShowBubble(
447    profiles::BubbleViewMode view_mode,
448    const signin::ManageAccountsParams& manage_accounts_params,
449    views::View* anchor_view,
450    views::BubbleBorder::Arrow arrow,
451    views::BubbleBorder::BubbleAlignment border_alignment,
452    Browser* browser) {
453  if (IsShowing())
454    return;
455
456  profile_bubble_ = new ProfileChooserView(anchor_view, arrow, browser,
457      view_mode, manage_accounts_params.service_type);
458  views::BubbleDelegateView::CreateBubble(profile_bubble_);
459  profile_bubble_->set_close_on_deactivate(close_on_deactivate_for_testing_);
460  profile_bubble_->SetAlignment(border_alignment);
461  profile_bubble_->GetWidget()->Show();
462  profile_bubble_->SetArrowPaintType(views::BubbleBorder::PAINT_NONE);
463}
464
465// static
466bool ProfileChooserView::IsShowing() {
467  return profile_bubble_ != NULL;
468}
469
470// static
471void ProfileChooserView::Hide() {
472  if (IsShowing())
473    profile_bubble_->GetWidget()->Close();
474}
475
476ProfileChooserView::ProfileChooserView(views::View* anchor_view,
477                                       views::BubbleBorder::Arrow arrow,
478                                       Browser* browser,
479                                       profiles::BubbleViewMode view_mode,
480                                       signin::GAIAServiceType service_type)
481    : BubbleDelegateView(anchor_view, arrow),
482      browser_(browser),
483      view_mode_(view_mode),
484      tutorial_mode_(profiles::TUTORIAL_MODE_NONE),
485      gaia_service_type_(service_type) {
486  // Reset the default margins inherited from the BubbleDelegateView.
487  set_margins(gfx::Insets());
488
489  ResetView();
490
491  avatar_menu_.reset(new AvatarMenu(
492      &g_browser_process->profile_manager()->GetProfileInfoCache(),
493      this,
494      browser_));
495  avatar_menu_->RebuildMenu();
496
497  ProfileOAuth2TokenService* oauth2_token_service =
498      ProfileOAuth2TokenServiceFactory::GetForProfile(browser_->profile());
499  if (oauth2_token_service)
500    oauth2_token_service->AddObserver(this);
501}
502
503ProfileChooserView::~ProfileChooserView() {
504  ProfileOAuth2TokenService* oauth2_token_service =
505      ProfileOAuth2TokenServiceFactory::GetForProfile(browser_->profile());
506  if (oauth2_token_service)
507    oauth2_token_service->RemoveObserver(this);
508}
509
510void ProfileChooserView::ResetView() {
511  question_mark_button_ = NULL;
512  manage_accounts_link_ = NULL;
513  signin_current_profile_link_ = NULL;
514  users_button_ = NULL;
515  lock_button_ = NULL;
516  add_account_link_ = NULL;
517  current_profile_photo_ = NULL;
518  current_profile_name_ = NULL;
519  tutorial_ok_button_ = NULL;
520  tutorial_learn_more_link_ = NULL;
521  tutorial_enable_new_profile_management_button_ = NULL;
522  tutorial_end_preview_link_ = NULL;
523  tutorial_send_feedback_button_ = NULL;
524  end_preview_and_relaunch_button_ = NULL;
525  end_preview_cancel_button_ = NULL;
526  remove_account_button_ = NULL;
527  account_removal_cancel_button_ = NULL;
528  gaia_signin_cancel_button_ = NULL;
529  open_other_profile_indexes_map_.clear();
530  delete_account_button_map_.clear();
531  reauth_account_button_map_.clear();
532  tutorial_mode_ = profiles::TUTORIAL_MODE_NONE;
533}
534
535void ProfileChooserView::Init() {
536  // If view mode is PROFILE_CHOOSER but there is an auth error, force
537  // ACCOUNT_MANAGEMENT mode.
538  if (view_mode_ == profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER &&
539      HasAuthError(browser_->profile())) {
540    view_mode_ = profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT;
541  }
542
543  ShowView(view_mode_, avatar_menu_.get());
544}
545
546void ProfileChooserView::OnAvatarMenuChanged(
547    AvatarMenu* avatar_menu) {
548  // Refresh the view with the new menu. We can't just update the local copy
549  // as this may have been triggered by a sign out action, in which case
550  // the view is being destroyed.
551  ShowView(profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER, avatar_menu);
552}
553
554void ProfileChooserView::OnRefreshTokenAvailable(
555    const std::string& account_id) {
556  // Refresh the account management view when a new account is added to the
557  // profile.
558  if (view_mode_ == profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT ||
559      view_mode_ == profiles::BUBBLE_VIEW_MODE_GAIA_SIGNIN ||
560      view_mode_ == profiles::BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT ||
561      view_mode_ == profiles::BUBBLE_VIEW_MODE_GAIA_REAUTH) {
562    ShowView(profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT, avatar_menu_.get());
563  }
564}
565
566void ProfileChooserView::OnRefreshTokenRevoked(const std::string& account_id) {
567  // Refresh the account management view when an account is removed from the
568  // profile.
569  if (view_mode_ == profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT)
570    ShowView(profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT, avatar_menu_.get());
571}
572
573void ProfileChooserView::ShowView(profiles::BubbleViewMode view_to_display,
574                                  AvatarMenu* avatar_menu) {
575  // The account management view should only be displayed if the active profile
576  // is signed in.
577  if (view_to_display == profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT) {
578    const AvatarMenu::Item& active_item = avatar_menu->GetItemAt(
579        avatar_menu->GetActiveProfileIndex());
580    DCHECK(active_item.signed_in);
581  }
582
583  // Records the last tutorial mode.
584  profiles::TutorialMode last_tutorial_mode = tutorial_mode_;
585  ResetView();
586  RemoveAllChildViews(true);
587  view_mode_ = view_to_display;
588
589  views::GridLayout* layout;
590  views::View* sub_view;
591  switch (view_mode_) {
592    case profiles::BUBBLE_VIEW_MODE_GAIA_SIGNIN:
593    case profiles::BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT:
594    case profiles::BUBBLE_VIEW_MODE_GAIA_REAUTH:
595      layout = CreateSingleColumnLayout(this, kFixedGaiaViewWidth);
596      sub_view = CreateGaiaSigninView();
597      break;
598    case profiles::BUBBLE_VIEW_MODE_ACCOUNT_REMOVAL:
599      layout = CreateSingleColumnLayout(this, kFixedAccountRemovalViewWidth);
600      sub_view = CreateAccountRemovalView();
601      break;
602    case profiles::BUBBLE_VIEW_MODE_END_PREVIEW:
603      layout = CreateSingleColumnLayout(this, kFixedEndPreviewViewWidth);
604      sub_view = CreateEndPreviewView();
605      break;
606    default:
607      layout = CreateSingleColumnLayout(this, kFixedMenuWidth);
608      sub_view = CreateProfileChooserView(avatar_menu, last_tutorial_mode);
609  }
610  sub_view->set_background(views::Background::CreateSolidBackground(
611      GetNativeTheme()->GetSystemColor(
612          ui::NativeTheme::kColorId_DialogBackground)));
613
614  layout->StartRow(1, 0);
615  layout->AddView(sub_view);
616  Layout();
617  if (GetBubbleFrameView())
618    SizeToContents();
619}
620
621void ProfileChooserView::WindowClosing() {
622  DCHECK_EQ(profile_bubble_, this);
623  profile_bubble_ = NULL;
624}
625
626void ProfileChooserView::ButtonPressed(views::Button* sender,
627                                       const ui::Event& event) {
628  // Disable button after clicking so that it doesn't get clicked twice and
629  // start a second action... which can crash Chrome.  But don't disable if it
630  // has no parent (like in tests) because that will also crash.
631  if (sender->parent())
632    sender->SetEnabled(false);
633
634  if (sender == users_button_) {
635    profiles::ShowUserManagerMaybeWithTutorial(browser_->profile());
636    // If this is a guest session, also close all the guest browser windows.
637    if (browser_->profile()->IsGuestSession())
638      profiles::CloseGuestProfileWindows();
639  } else if (sender == lock_button_) {
640    profiles::LockProfile(browser_->profile());
641    PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_LOCK);
642  } else if (sender == tutorial_ok_button_) {
643    // If the user manually dismissed the tutorial, never show it again by
644    // setting the number of times shown to the maximum plus 1, so that later we
645    // could distinguish between the dismiss case and the case when the tutorial
646    // is indeed shown for the maximum number of times.
647    browser_->profile()->GetPrefs()->SetInteger(
648        prefs::kProfileAvatarTutorialShown, kProfileAvatarTutorialShowMax + 1);
649
650    ProfileMetrics::LogProfileUpgradeEnrollment(
651        ProfileMetrics::PROFILE_ENROLLMENT_CLOSE_WELCOME_CARD);
652    ShowView(profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER, avatar_menu_.get());
653  } else if (sender == tutorial_enable_new_profile_management_button_) {
654    ProfileMetrics::LogProfileUpgradeEnrollment(
655        ProfileMetrics::PROFILE_ENROLLMENT_ACCEPT_NEW_PROFILE_MGMT);
656    profiles::EnableNewProfileManagementPreview(browser_->profile());
657  } else if (sender == remove_account_button_) {
658    RemoveAccount();
659  } else if (sender == account_removal_cancel_button_) {
660    account_id_to_remove_.clear();
661    ShowView(profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT, avatar_menu_.get());
662  } else if (sender == gaia_signin_cancel_button_) {
663    std::string primary_account =
664        SigninManagerFactory::GetForProfile(browser_->profile())->
665        GetAuthenticatedUsername();
666    ShowView(primary_account.empty() ?
667                 profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER :
668                 profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT,
669             avatar_menu_.get());
670  } else if (sender == question_mark_button_) {
671    tutorial_mode_ = profiles::TUTORIAL_MODE_SEND_FEEDBACK;
672    ShowView(profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER, avatar_menu_.get());
673  } else if (sender == tutorial_send_feedback_button_) {
674    ProfileMetrics::LogProfileUpgradeEnrollment(
675        ProfileMetrics::PROFILE_ENROLLMENT_SEND_FEEDBACK);
676    chrome::OpenFeedbackDialog(browser_);
677  } else if (sender == end_preview_and_relaunch_button_) {
678    ProfileMetrics::LogProfileUpgradeEnrollment(
679        ProfileMetrics::PROFILE_ENROLLMENT_DISABLE_NEW_PROFILE_MGMT);
680    profiles::DisableNewProfileManagementPreview(browser_->profile());
681  } else if (sender == end_preview_cancel_button_) {
682    tutorial_mode_ = profiles::TUTORIAL_MODE_SEND_FEEDBACK;
683    ShowView(profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER, avatar_menu_.get());
684  } else if (current_profile_photo_ &&
685             sender == current_profile_photo_->change_photo_button()) {
686    avatar_menu_->EditProfile(avatar_menu_->GetActiveProfileIndex());
687    PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_EDIT_IMAGE);
688  } else if (sender == signin_current_profile_link_) {
689    // Only show the inline signin if the new UI flag is flipped. Otherwise,
690    // use the tab signin page.
691    if (switches::IsNewProfileManagement())
692      ShowView(profiles::BUBBLE_VIEW_MODE_GAIA_SIGNIN, avatar_menu_.get());
693    else
694      chrome::ShowBrowserSignin(browser_, signin::SOURCE_MENU);
695  } else {
696    // Either one of the "other profiles", or one of the profile accounts
697    // buttons was pressed.
698    ButtonIndexes::const_iterator profile_match =
699        open_other_profile_indexes_map_.find(sender);
700    if (profile_match != open_other_profile_indexes_map_.end()) {
701      avatar_menu_->SwitchToProfile(
702          profile_match->second,
703          ui::DispositionFromEventFlags(event.flags()) == NEW_WINDOW,
704          ProfileMetrics::SWITCH_PROFILE_ICON);
705    } else {
706      // This was a profile accounts button.
707      AccountButtonIndexes::const_iterator account_match =
708          delete_account_button_map_.find(sender);
709      if (account_match != delete_account_button_map_.end()) {
710        account_id_to_remove_ = account_match->second;
711        ShowView(profiles::BUBBLE_VIEW_MODE_ACCOUNT_REMOVAL,
712            avatar_menu_.get());
713      } else {
714        account_match = reauth_account_button_map_.find(sender);
715        DCHECK(account_match != reauth_account_button_map_.end());
716        ShowView(profiles::BUBBLE_VIEW_MODE_GAIA_REAUTH, avatar_menu_.get());
717      }
718    }
719  }
720}
721
722void ProfileChooserView::RemoveAccount() {
723  DCHECK(!account_id_to_remove_.empty());
724  MutableProfileOAuth2TokenService* oauth2_token_service =
725      ProfileOAuth2TokenServiceFactory::GetPlatformSpecificForProfile(
726      browser_->profile());
727  if (oauth2_token_service) {
728    oauth2_token_service->RevokeCredentials(account_id_to_remove_);
729    PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_REMOVE_ACCT);
730  }
731  account_id_to_remove_.clear();
732
733  ShowView(profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT, avatar_menu_.get());
734}
735
736void ProfileChooserView::LinkClicked(views::Link* sender, int event_flags) {
737  if (sender == manage_accounts_link_) {
738    // This link can either mean show/hide the account management view,
739    // depending on which view it is displayed. ShowView() will DCHECK if
740    // the account management view is displayed for non signed-in users.
741    ShowView(
742        view_mode_ == profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT ?
743            profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER :
744            profiles::BUBBLE_VIEW_MODE_ACCOUNT_MANAGEMENT,
745        avatar_menu_.get());
746  } else if (sender == add_account_link_) {
747    ShowView(profiles::BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT, avatar_menu_.get());
748    PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_ADD_ACCT);
749  } else if (sender == tutorial_learn_more_link_) {
750    ProfileMetrics::LogProfileUpgradeEnrollment(
751        ProfileMetrics::PROFILE_ENROLLMENT_LAUNCH_LEARN_MORE);
752    // TODO(guohui): update |learn_more_url| once it is decided.
753    const GURL lear_more_url("https://support.google.com/chrome/?hl=en#to");
754    chrome::NavigateParams params(
755        browser_->profile(),
756        lear_more_url,
757        content::PAGE_TRANSITION_LINK);
758    params.disposition = NEW_FOREGROUND_TAB;
759    chrome::Navigate(&params);
760  } else {
761    DCHECK(sender == tutorial_end_preview_link_);
762    ShowView(profiles::BUBBLE_VIEW_MODE_END_PREVIEW, avatar_menu_.get());
763  }
764}
765
766void ProfileChooserView::StyledLabelLinkClicked(
767    const gfx::Range& range, int event_flags) {
768  chrome::ShowSettings(browser_);
769}
770
771bool ProfileChooserView::HandleKeyEvent(views::Textfield* sender,
772                                        const ui::KeyEvent& key_event) {
773  views::Textfield* name_textfield =
774      current_profile_name_->profile_name_textfield();
775  DCHECK(sender == name_textfield);
776
777  if (key_event.key_code() == ui::VKEY_RETURN ||
778      key_event.key_code() == ui::VKEY_TAB) {
779    // Pressing Tab/Enter commits the new profile name, unless it's empty.
780    base::string16 new_profile_name = name_textfield->text();
781    if (new_profile_name.empty())
782      return true;
783
784    const AvatarMenu::Item& active_item = avatar_menu_->GetItemAt(
785        avatar_menu_->GetActiveProfileIndex());
786    Profile* profile = g_browser_process->profile_manager()->GetProfile(
787        active_item.profile_path);
788    DCHECK(profile);
789
790    if (profile->IsSupervised())
791      return true;
792
793    profiles::UpdateProfileName(profile, new_profile_name);
794    PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_EDIT_NAME);
795    current_profile_name_->ShowReadOnlyView();
796    return true;
797  }
798  return false;
799}
800
801void ProfileChooserView::PostActionPerformed(
802    ProfileMetrics::ProfileDesktopMenu action_performed) {
803  ProfileMetrics::LogProfileDesktopMenu(action_performed, gaia_service_type_);
804  gaia_service_type_ = signin::GAIA_SERVICE_TYPE_NONE;
805}
806
807views::View* ProfileChooserView::CreateProfileChooserView(
808    AvatarMenu* avatar_menu,
809    profiles::TutorialMode last_tutorial_mode) {
810  // TODO(guohui, noms): the view should be customized based on whether new
811  // profile management preview is enabled or not.
812
813  views::View* view = new views::View();
814  views::GridLayout* layout = CreateSingleColumnLayout(view, kFixedMenuWidth);
815  // Separate items into active and alternatives.
816  Indexes other_profiles;
817  views::View* tutorial_view = NULL;
818  views::View* current_profile_view = NULL;
819  views::View* current_profile_accounts = NULL;
820  views::View* option_buttons_view = NULL;
821  bool is_new_profile_management = switches::IsNewProfileManagement();
822  for (size_t i = 0; i < avatar_menu->GetNumberOfItems(); ++i) {
823    const AvatarMenu::Item& item = avatar_menu->GetItemAt(i);
824    if (item.active) {
825      option_buttons_view = CreateOptionsView(item.signed_in);
826      current_profile_view = CreateCurrentProfileView(item, false);
827      if (view_mode_ == profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER) {
828        if (is_new_profile_management) {
829          tutorial_view =
830              last_tutorial_mode == profiles::TUTORIAL_MODE_SEND_FEEDBACK ?
831              CreateSendPreviewFeedbackView() :
832              CreatePreviewEnabledTutorialView(
833                  item, last_tutorial_mode == profiles::TUTORIAL_MODE_WELCOME);
834        } else {
835          tutorial_view = CreateNewProfileManagementPreviewView();
836        }
837      } else {
838        current_profile_accounts = CreateCurrentProfileAccountsView(item);
839      }
840    } else {
841      other_profiles.push_back(i);
842    }
843  }
844
845  if (tutorial_view) {
846    // Be sure not to track the tutorial display on View refresh, and only count
847    // the preview-promo view, shown when New Profile Management is off.
848    if (tutorial_mode_ != last_tutorial_mode && !is_new_profile_management) {
849      ProfileMetrics::LogProfileUpgradeEnrollment(
850          ProfileMetrics::PROFILE_ENROLLMENT_SHOW_PREVIEW_PROMO);
851    }
852    layout->StartRow(1, 0);
853    layout->AddView(tutorial_view);
854  }
855
856  if (!current_profile_view) {
857    // Guest windows don't have an active profile.
858    current_profile_view = CreateGuestProfileView();
859    option_buttons_view = CreateOptionsView(false);
860  }
861
862  layout->StartRow(1, 0);
863  layout->AddView(current_profile_view);
864
865  if (view_mode_ != profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER) {
866    DCHECK(current_profile_accounts);
867    layout->StartRow(0, 0);
868    layout->AddView(new views::Separator(views::Separator::HORIZONTAL));
869    layout->StartRow(1, 0);
870    layout->AddView(current_profile_accounts);
871  }
872
873  if (browser_->profile()->IsSupervised()) {
874    layout->StartRow(0, 0);
875    layout->AddView(new views::Separator(views::Separator::HORIZONTAL));
876    layout->StartRow(1, 0);
877    layout->AddView(CreateSupervisedUserDisclaimerView());
878  }
879
880  if (view_mode_ == profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER) {
881    layout->StartRow(1, 0);
882    if (switches::IsFastUserSwitching())
883      layout->AddView(CreateOtherProfilesView(other_profiles));
884  }
885
886  layout->StartRow(0, 0);
887  layout->AddView(new views::Separator(views::Separator::HORIZONTAL));
888
889  // Option buttons. Only available with the new profile management flag.
890  if (option_buttons_view) {
891    layout->StartRow(0, 0);
892    layout->AddView(option_buttons_view);
893  }
894
895  return view;
896}
897
898views::View* ProfileChooserView::CreatePreviewEnabledTutorialView(
899    const AvatarMenu::Item& current_avatar_item,
900    bool tutorial_shown) {
901  if (!switches::IsNewProfileManagementPreviewEnabled())
902    return NULL;
903
904  Profile* profile = browser_->profile();
905  const int show_count = profile->GetPrefs()->GetInteger(
906      prefs::kProfileAvatarTutorialShown);
907  // Do not show the tutorial if user has dismissed it.
908  if (show_count > kProfileAvatarTutorialShowMax)
909    return NULL;
910
911  if (!tutorial_shown) {
912    if (show_count == kProfileAvatarTutorialShowMax)
913      return NULL;
914    profile->GetPrefs()->SetInteger(
915        prefs::kProfileAvatarTutorialShown, show_count + 1);
916  }
917
918  return CreateTutorialView(
919      profiles::TUTORIAL_MODE_WELCOME,
920      l10n_util::GetStringUTF16(IDS_PROFILES_PREVIEW_ENABLED_TUTORIAL_TITLE),
921      l10n_util::GetStringUTF16(
922          IDS_PROFILES_PREVIEW_ENABLED_TUTORIAL_CONTENT_TEXT),
923      l10n_util::GetStringUTF16(IDS_PROFILES_PROFILE_TUTORIAL_LEARN_MORE),
924      l10n_util::GetStringUTF16(IDS_PROFILES_TUTORIAL_OK_BUTTON),
925      &tutorial_learn_more_link_,
926      &tutorial_ok_button_);
927}
928
929views::View* ProfileChooserView::CreateSendPreviewFeedbackView() {
930  return CreateTutorialView(
931      profiles::TUTORIAL_MODE_SEND_FEEDBACK,
932      l10n_util::GetStringUTF16(IDS_PROFILES_FEEDBACK_TUTORIAL_TITLE),
933      l10n_util::GetStringUTF16(
934          IDS_PROFILES_FEEDBACK_TUTORIAL_CONTENT_TEXT),
935      l10n_util::GetStringUTF16(IDS_PROFILES_END_PREVIEW),
936      l10n_util::GetStringUTF16(IDS_PROFILES_SEND_FEEDBACK_BUTTON),
937      &tutorial_end_preview_link_,
938      &tutorial_send_feedback_button_);
939}
940
941views::View* ProfileChooserView::CreateTutorialView(
942    profiles::TutorialMode tutorial_mode,
943    const base::string16& title_text,
944    const base::string16& content_text,
945    const base::string16& link_text,
946    const base::string16& button_text,
947    views::Link** link,
948    views::LabelButton** button) {
949  tutorial_mode_ = tutorial_mode;
950
951  views::View* view = new views::View();
952  view->set_background(views::Background::CreateSolidBackground(
953      profiles::kAvatarTutorialBackgroundColor));
954  views::GridLayout* layout = CreateSingleColumnLayout(view,
955      kFixedMenuWidth - 2 * views::kButtonHEdgeMarginNew);
956  layout->SetInsets(views::kButtonVEdgeMarginNew,
957                    views::kButtonHEdgeMarginNew,
958                    views::kButtonVEdgeMarginNew,
959                    views::kButtonHEdgeMarginNew);
960
961  // Adds title.
962  views::Label* title_label = new views::Label(title_text);
963  title_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
964  title_label->SetAutoColorReadabilityEnabled(false);
965  title_label->SetEnabledColor(SK_ColorWHITE);
966  title_label->SetFontList(ui::ResourceBundle::GetSharedInstance().GetFontList(
967      ui::ResourceBundle::MediumFont));
968  layout->StartRow(1, 0);
969  layout->AddView(title_label);
970
971  // Adds body content.
972  views::Label* content_label = new views::Label(content_text);
973  content_label->SetMultiLine(true);
974  content_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
975  content_label->SetAutoColorReadabilityEnabled(false);
976  content_label->SetEnabledColor(profiles::kAvatarTutorialContentTextColor);
977  layout->StartRowWithPadding(1, 0, 0, views::kRelatedControlVerticalSpacing);
978  layout->AddView(content_label);
979
980  // Adds links and buttons.
981  views::View* button_row = new views::View();
982  views::GridLayout* button_layout = new views::GridLayout(button_row);
983  views::ColumnSet* button_columns = button_layout->AddColumnSet(0);
984  button_columns->AddColumn(views::GridLayout::LEADING,
985      views::GridLayout::CENTER, 0, views::GridLayout::USE_PREF, 0, 0);
986  button_columns->AddPaddingColumn(
987      1, views::kUnrelatedControlHorizontalSpacing);
988  button_columns->AddColumn(views::GridLayout::TRAILING,
989      views::GridLayout::CENTER, 0, views::GridLayout::USE_PREF, 0, 0);
990  button_row->SetLayoutManager(button_layout);
991
992  *link = CreateLink(link_text, this);
993  (*link)->SetHorizontalAlignment(gfx::ALIGN_LEFT);
994  (*link)->SetAutoColorReadabilityEnabled(false);
995  (*link)->SetEnabledColor(SK_ColorWHITE);
996  button_layout->StartRow(1, 0);
997  button_layout->AddView(*link);
998
999  *button = new views::LabelButton(this, button_text);
1000  (*button)->SetHorizontalAlignment(gfx::ALIGN_CENTER);
1001  (*button)->SetStyle(views::Button::STYLE_BUTTON);
1002  button_layout->AddView(*button);
1003
1004  layout->StartRowWithPadding(1, 0, 0, views::kUnrelatedControlVerticalSpacing);
1005  layout->AddView(button_row);
1006
1007  // Adds a padded caret image at the bottom.
1008  views::View* padded_caret_view = new views::View();
1009  views::GridLayout* padded_caret_layout =
1010      new views::GridLayout(padded_caret_view);
1011  views::ColumnSet* padded_columns = padded_caret_layout->AddColumnSet(0);
1012  padded_columns->AddPaddingColumn(0, views::kButtonHEdgeMarginNew);
1013  padded_columns->AddColumn(views::GridLayout::LEADING,
1014      views::GridLayout::CENTER, 0, views::GridLayout::USE_PREF, 0, 0);
1015  padded_caret_view->SetLayoutManager(padded_caret_layout);
1016
1017  views::ImageView* caret_image_view = new views::ImageView();
1018  ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
1019  caret_image_view->SetImage(
1020      *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_CARET));
1021
1022  padded_caret_layout->StartRow(1, 0);
1023  padded_caret_layout->AddView(caret_image_view);
1024
1025  views::View* view_with_caret = new views::View();
1026  views::GridLayout* layout_with_caret =
1027      CreateSingleColumnLayout(view_with_caret, kFixedMenuWidth);
1028  layout_with_caret->StartRow(1, 0);
1029  layout_with_caret->AddView(view);
1030  layout_with_caret->StartRow(1, 0);
1031  layout_with_caret->AddView(padded_caret_view);
1032  return view_with_caret;
1033}
1034
1035views::View* ProfileChooserView::CreateCurrentProfileView(
1036    const AvatarMenu::Item& avatar_item,
1037    bool is_guest) {
1038  views::View* view = new views::View();
1039  int column_width = kFixedMenuWidth - 2 * views::kButtonHEdgeMarginNew;
1040  views::GridLayout* layout = CreateSingleColumnLayout(view, column_width);
1041  layout->SetInsets(views::kButtonVEdgeMarginNew,
1042                    views::kButtonHEdgeMarginNew,
1043                    views::kUnrelatedControlVerticalSpacing,
1044                    views::kButtonHEdgeMarginNew);
1045
1046  // Profile icon, centered.
1047  int x_offset = (column_width - kLargeImageSide) / 2;
1048  current_profile_photo_ = new EditableProfilePhoto(
1049      this, avatar_item.icon, !is_guest,
1050      gfx::Rect(x_offset, 0, kLargeImageSide, kLargeImageSide));
1051  SizedContainer* profile_icon_container =
1052      new SizedContainer(gfx::Size(column_width, kLargeImageSide));
1053  profile_icon_container->AddChildView(current_profile_photo_);
1054
1055  if (switches::IsNewProfileManagementPreviewEnabled()) {
1056    question_mark_button_ = new views::ImageButton(this);
1057    question_mark_button_->SetImageAlignment(
1058        views::ImageButton::ALIGN_LEFT, views::ImageButton::ALIGN_MIDDLE);
1059    ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
1060    question_mark_button_->SetImage(views::ImageButton::STATE_NORMAL,
1061        rb->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_QUESTION_STABLE));
1062    question_mark_button_->SetImage(views::ImageButton::STATE_HOVERED,
1063        rb->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_QUESTION_HOVER));
1064    question_mark_button_->SetImage(views::ImageButton::STATE_PRESSED,
1065        rb->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_QUESTION_SELECT));
1066    gfx::Size preferred_size = question_mark_button_->GetPreferredSize();
1067    question_mark_button_->SetBounds(
1068        0, 0, preferred_size.width(), preferred_size.height());
1069    profile_icon_container->AddChildView(question_mark_button_);
1070  }
1071
1072  if (browser_->profile()->IsSupervised()) {
1073    views::ImageView* supervised_icon = new views::ImageView();
1074    ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
1075    supervised_icon->SetImage(
1076        rb->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_SUPERVISED));
1077    gfx::Size preferred_size = supervised_icon->GetPreferredSize();
1078    gfx::Rect parent_bounds = current_profile_photo_->bounds();
1079    supervised_icon->SetBounds(
1080        parent_bounds.right() - preferred_size.width(),
1081        parent_bounds.bottom() - preferred_size.height(),
1082        preferred_size.width(),
1083        preferred_size.height());
1084    profile_icon_container->AddChildView(supervised_icon);
1085  }
1086
1087  layout->StartRow(1, 0);
1088  layout->AddView(profile_icon_container);
1089
1090  // Profile name, centered.
1091  bool editing_allowed = !is_guest && !browser_->profile()->IsSupervised();
1092  current_profile_name_ = new EditableProfileName(
1093      this, profiles::GetAvatarNameForProfile(browser_->profile()),
1094                                              editing_allowed);
1095  layout->StartRow(1, 0);
1096  layout->AddView(current_profile_name_);
1097
1098  if (is_guest)
1099    return view;
1100
1101  // The available links depend on the type of profile that is active.
1102  if (avatar_item.signed_in) {
1103    layout->StartRow(1, 0);
1104    if (switches::IsNewProfileManagement()) {
1105      base::string16 link_title = l10n_util::GetStringUTF16(
1106          view_mode_ == profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER ?
1107              IDS_PROFILES_PROFILE_MANAGE_ACCOUNTS_BUTTON :
1108              IDS_PROFILES_PROFILE_HIDE_MANAGE_ACCOUNTS_BUTTON);
1109      manage_accounts_link_ = CreateLink(link_title, this);
1110      manage_accounts_link_->SetHorizontalAlignment(gfx::ALIGN_CENTER);
1111      layout->AddView(manage_accounts_link_);
1112    } else {
1113      views::Label* email_label = new views::Label(avatar_item.sync_state);
1114      email_label->SetHorizontalAlignment(gfx::ALIGN_CENTER);
1115      layout->AddView(email_label);
1116    }
1117  } else {
1118    SigninManagerBase* signin_manager =
1119        SigninManagerFactory::GetForProfile(
1120            browser_->profile()->GetOriginalProfile());
1121    if (signin_manager->IsSigninAllowed()) {
1122      signin_current_profile_link_ = new views::BlueButton(
1123        this, l10n_util::GetStringFUTF16(IDS_SYNC_START_SYNC_BUTTON_LABEL,
1124            l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME)));
1125      layout->StartRow(1, 0);
1126      layout->AddView(signin_current_profile_link_);
1127    }
1128  }
1129
1130  return view;
1131}
1132
1133views::View* ProfileChooserView::CreateGuestProfileView() {
1134  gfx::Image guest_icon =
1135      ui::ResourceBundle::GetSharedInstance().GetImageNamed(
1136          profiles::GetPlaceholderAvatarIconResourceID());
1137  AvatarMenu::Item guest_avatar_item(0, 0, guest_icon);
1138  guest_avatar_item.active = true;
1139  guest_avatar_item.name = l10n_util::GetStringUTF16(
1140      IDS_PROFILES_GUEST_PROFILE_NAME);
1141  guest_avatar_item.signed_in = false;
1142
1143  return CreateCurrentProfileView(guest_avatar_item, true);
1144}
1145
1146views::View* ProfileChooserView::CreateOtherProfilesView(
1147    const Indexes& avatars_to_show) {
1148  views::View* view = new views::View();
1149  views::GridLayout* layout = CreateSingleColumnLayout(view, kFixedMenuWidth);
1150
1151  int num_avatars_to_show = avatars_to_show.size();
1152  for (int i = 0; i < num_avatars_to_show; ++i) {
1153    const size_t index = avatars_to_show[i];
1154    const AvatarMenu::Item& item = avatar_menu_->GetItemAt(index);
1155    const int kSmallImageSide = 32;
1156
1157    gfx::Image image = profiles::GetSizedAvatarIcon(
1158        item.icon, true, kSmallImageSide, kSmallImageSide);
1159
1160    views::LabelButton* button = new BackgroundColorHoverButton(
1161        this,
1162        item.name,
1163        *image.ToImageSkia(),
1164        *image.ToImageSkia());
1165    button->set_min_size(gfx::Size(
1166        0, kButtonHeight + views::kRelatedControlVerticalSpacing));
1167
1168    open_other_profile_indexes_map_[button] = index;
1169
1170    layout->StartRow(1, 0);
1171    layout->AddView(new views::Separator(views::Separator::HORIZONTAL));
1172    layout->StartRow(1, 0);
1173    layout->AddView(button);
1174  }
1175
1176  return view;
1177}
1178
1179views::View* ProfileChooserView::CreateOptionsView(bool enable_lock) {
1180  if (!switches::IsNewProfileManagement())
1181    return NULL;
1182
1183  views::View* view = new views::View();
1184  views::GridLayout* layout;
1185
1186  // Only signed-in users have the ability to lock.
1187  if (enable_lock) {
1188    layout = new views::GridLayout(view);
1189    views::ColumnSet* columns = layout->AddColumnSet(0);
1190    int width_of_lock_button =
1191        2 * views::kUnrelatedControlLargeHorizontalSpacing + 12;
1192    int width_of_users_button = kFixedMenuWidth - width_of_lock_button;
1193    columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 0,
1194                       views::GridLayout::FIXED, width_of_users_button,
1195                       width_of_users_button);
1196    columns->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 0,
1197                       views::GridLayout::FIXED, width_of_lock_button,
1198                       width_of_lock_button);
1199    view->SetLayoutManager(layout);
1200  } else {
1201    layout = CreateSingleColumnLayout(view, kFixedMenuWidth);
1202  }
1203
1204  base::string16 text = browser_->profile()->IsGuestSession() ?
1205      l10n_util::GetStringUTF16(IDS_PROFILES_EXIT_GUEST) :
1206      l10n_util::GetStringFUTF16(IDS_PROFILES_NOT_YOU_BUTTON,
1207          profiles::GetAvatarNameForProfile(browser_->profile()));
1208  ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
1209  users_button_ = new BackgroundColorHoverButton(
1210      this,
1211      text,
1212      *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_AVATAR),
1213      *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_AVATAR));
1214  users_button_->set_min_size(gfx::Size(
1215      0, kButtonHeight + views::kRelatedControlVerticalSpacing));
1216
1217  layout->StartRow(1, 0);
1218  layout->AddView(users_button_);
1219
1220  if (enable_lock) {
1221    lock_button_ = new BackgroundColorHoverButton(
1222        this,
1223        base::string16(),
1224        *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_LOCK),
1225        *rb->GetImageSkiaNamed(IDR_ICON_PROFILES_MENU_LOCK));
1226    lock_button_->set_min_size(gfx::Size(
1227      0, kButtonHeight + views::kRelatedControlVerticalSpacing));
1228    layout->AddView(lock_button_);
1229  }
1230  return view;
1231}
1232
1233views::View* ProfileChooserView::CreateSupervisedUserDisclaimerView() {
1234  views::View* view = new views::View();
1235  views::GridLayout* layout = CreateSingleColumnLayout(
1236      view, kFixedMenuWidth - 2 * views::kButtonHEdgeMarginNew);
1237  layout->SetInsets(views::kRelatedControlVerticalSpacing,
1238                    views::kButtonHEdgeMarginNew,
1239                    views::kRelatedControlVerticalSpacing,
1240                    views::kButtonHEdgeMarginNew);
1241  views::Label* disclaimer = new views::Label(
1242      avatar_menu_->GetSupervisedUserInformation());
1243  disclaimer->SetMultiLine(true);
1244  disclaimer->SetHorizontalAlignment(gfx::ALIGN_LEFT);
1245  ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
1246  disclaimer->SetFontList(rb->GetFontList(ui::ResourceBundle::SmallFont));
1247  layout->StartRow(1, 0);
1248  layout->AddView(disclaimer);
1249
1250  return view;
1251}
1252
1253views::View* ProfileChooserView::CreateCurrentProfileAccountsView(
1254    const AvatarMenu::Item& avatar_item) {
1255  DCHECK(avatar_item.signed_in);
1256  views::View* view = new views::View();
1257  view->set_background(views::Background::CreateSolidBackground(
1258      profiles::kAvatarBubbleAccountsBackgroundColor));
1259  views::GridLayout* layout = CreateSingleColumnLayout(view, kFixedMenuWidth);
1260
1261  Profile* profile = browser_->profile();
1262  std::string primary_account =
1263      SigninManagerFactory::GetForProfile(profile)->GetAuthenticatedUsername();
1264  DCHECK(!primary_account.empty());
1265  std::vector<std::string>accounts =
1266      profiles::GetSecondaryAccountsForProfile(profile, primary_account);
1267
1268  // Get state of authentication error, if any.
1269  std::string error_account_id = GetAuthErrorAccountId(profile);
1270
1271  // The primary account should always be listed first.
1272  // TODO(rogerta): we still need to further differentiate the primary account
1273  // from the others in the UI, so more work is likely required here:
1274  // crbug.com/311124.
1275  CreateAccountButton(layout, primary_account, true,
1276                      error_account_id == primary_account, kFixedMenuWidth);
1277  for (size_t i = 0; i < accounts.size(); ++i)
1278    CreateAccountButton(layout, accounts[i], false,
1279                        error_account_id == accounts[i], kFixedMenuWidth);
1280  layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
1281
1282  add_account_link_ = CreateLink(l10n_util::GetStringFUTF16(
1283      IDS_PROFILES_PROFILE_ADD_ACCOUNT_BUTTON, avatar_item.name), this);
1284  add_account_link_->SetBorder(views::Border::CreateEmptyBorder(
1285      0, views::kButtonVEdgeMarginNew,
1286      views::kRelatedControlVerticalSpacing, 0));
1287  layout->StartRow(1, 0);
1288  layout->AddView(add_account_link_);
1289  return view;
1290}
1291
1292void ProfileChooserView::CreateAccountButton(views::GridLayout* layout,
1293                                             const std::string& account,
1294                                             bool is_primary_account,
1295                                             bool reauth_required,
1296                                             int width) {
1297  ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
1298  const gfx::ImageSkia* delete_default_image =
1299      rb->GetImageNamed(IDR_CLOSE_1).ToImageSkia();
1300  const int kDeleteButtonWidth = delete_default_image->width();
1301  const gfx::ImageSkia warning_default_image = reauth_required ?
1302      *rb->GetImageNamed(IDR_ICON_PROFILES_ACCOUNT_BUTTON_ERROR).ToImageSkia() :
1303      gfx::ImageSkia();
1304  const int kWarningButtonWidth = reauth_required ?
1305      warning_default_image.width() + views::kRelatedButtonHSpacing : 0;
1306  int available_width = width - 2 * views::kButtonHEdgeMarginNew
1307      - kDeleteButtonWidth - kWarningButtonWidth;
1308  views::LabelButton* email_button = new BackgroundColorHoverButton(
1309      reauth_required ? this : NULL,
1310      gfx::ElideText(base::UTF8ToUTF16(account), gfx::FontList(),
1311                     available_width, gfx::ELIDE_EMAIL),
1312      warning_default_image,
1313      warning_default_image);
1314  layout->StartRow(1, 0);
1315  layout->AddView(email_button);
1316
1317  // Delete button.
1318  views::ImageButton* delete_button = new views::ImageButton(this);
1319  delete_button->SetImageAlignment(views::ImageButton::ALIGN_RIGHT,
1320                                   views::ImageButton::ALIGN_MIDDLE);
1321  delete_button->SetImage(views::ImageButton::STATE_NORMAL,
1322                          delete_default_image);
1323  delete_button->SetImage(views::ImageButton::STATE_HOVERED,
1324                          rb->GetImageSkiaNamed(IDR_CLOSE_1_H));
1325  delete_button->SetImage(views::ImageButton::STATE_PRESSED,
1326                          rb->GetImageSkiaNamed(IDR_CLOSE_1_P));
1327  delete_button->SetBounds(
1328      width - views::kButtonHEdgeMarginNew - kDeleteButtonWidth,
1329      0, kDeleteButtonWidth, kButtonHeight);
1330
1331  email_button->set_notify_enter_exit_on_child(true);
1332  email_button->AddChildView(delete_button);
1333
1334  // Save the original email address, as the button text could be elided.
1335  delete_account_button_map_[delete_button] = account;
1336  if (reauth_required)
1337    reauth_account_button_map_[email_button] = account;
1338}
1339
1340views::View* ProfileChooserView::CreateGaiaSigninView() {
1341  GURL url;
1342  int message_id;
1343
1344  switch (view_mode_) {
1345    case profiles::BUBBLE_VIEW_MODE_GAIA_SIGNIN:
1346      url = signin::GetPromoURL(signin::SOURCE_AVATAR_BUBBLE_SIGN_IN,
1347                                false /* auto_close */,
1348                                true /* is_constrained */);
1349      message_id = IDS_PROFILES_GAIA_SIGNIN_TITLE;
1350      break;
1351    case profiles::BUBBLE_VIEW_MODE_GAIA_ADD_ACCOUNT:
1352      url = signin::GetPromoURL(signin::SOURCE_AVATAR_BUBBLE_ADD_ACCOUNT,
1353                                false /* auto_close */,
1354                                true /* is_constrained */);
1355      message_id = IDS_PROFILES_GAIA_ADD_ACCOUNT_TITLE;
1356      break;
1357    case profiles::BUBBLE_VIEW_MODE_GAIA_REAUTH: {
1358      DCHECK(HasAuthError(browser_->profile()));
1359      url = signin::GetReauthURL(browser_->profile(),
1360                                 GetAuthErrorUsername(browser_->profile()));
1361      message_id = IDS_PROFILES_GAIA_REAUTH_TITLE;
1362      break;
1363    }
1364    default:
1365      NOTREACHED() << "Called with invalid mode=" << view_mode_;
1366      return NULL;
1367  }
1368
1369  // Adds Gaia signin webview
1370  Profile* profile = browser_->profile();
1371  views::WebView* web_view = new views::WebView(profile);
1372  web_view->LoadInitialURL(url);
1373  web_view->SetPreferredSize(
1374      gfx::Size(kFixedGaiaViewWidth, kFixedGaiaViewHeight));
1375
1376  TitleCard* title_card = new TitleCard(message_id, this,
1377                                        &gaia_signin_cancel_button_);
1378  return TitleCard::AddPaddedTitleCard(
1379      web_view, title_card, kFixedGaiaViewWidth);
1380}
1381
1382views::View* ProfileChooserView::CreateAccountRemovalView() {
1383  views::View* view = new views::View();
1384  views::GridLayout* layout = CreateSingleColumnLayout(
1385      view, kFixedAccountRemovalViewWidth - 2 * views::kButtonHEdgeMarginNew);
1386  layout->SetInsets(0,
1387                    views::kButtonHEdgeMarginNew,
1388                    views::kButtonVEdgeMarginNew,
1389                    views::kButtonHEdgeMarginNew);
1390
1391  const std::string& primary_account = SigninManagerFactory::GetForProfile(
1392      browser_->profile())->GetAuthenticatedUsername();
1393  bool is_primary_account = primary_account == account_id_to_remove_;
1394
1395  // Adds main text.
1396  layout->StartRowWithPadding(1, 0, 0, views::kUnrelatedControlVerticalSpacing);
1397  ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
1398  const gfx::FontList& small_font_list =
1399      rb->GetFontList(ui::ResourceBundle::SmallFont);
1400
1401  if (is_primary_account) {
1402    std::vector<size_t> offsets;
1403    const base::string16 settings_text =
1404        l10n_util::GetStringUTF16(IDS_PROFILES_SETTINGS_LINK);
1405    const base::string16 primary_account_removal_text =
1406        l10n_util::GetStringFUTF16(IDS_PROFILES_PRIMARY_ACCOUNT_REMOVAL_TEXT,
1407            base::UTF8ToUTF16(account_id_to_remove_), settings_text, &offsets);
1408    views::StyledLabel* primary_account_removal_label =
1409        new views::StyledLabel(primary_account_removal_text, this);
1410    primary_account_removal_label->AddStyleRange(
1411        gfx::Range(offsets[1], offsets[1] + settings_text.size()),
1412        views::StyledLabel::RangeStyleInfo::CreateForLink());
1413    primary_account_removal_label->SetBaseFontList(small_font_list);
1414    layout->AddView(primary_account_removal_label);
1415  } else {
1416    views::Label* content_label = new views::Label(
1417        l10n_util::GetStringUTF16(IDS_PROFILES_ACCOUNT_REMOVAL_TEXT));
1418    content_label->SetMultiLine(true);
1419    content_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
1420    content_label->SetFontList(small_font_list);
1421    layout->AddView(content_label);
1422  }
1423
1424  // Adds button.
1425  if (!is_primary_account) {
1426    remove_account_button_ = new views::BlueButton(
1427        this, l10n_util::GetStringUTF16(IDS_PROFILES_ACCOUNT_REMOVAL_BUTTON));
1428    remove_account_button_->SetHorizontalAlignment(
1429        gfx::ALIGN_CENTER);
1430    layout->StartRowWithPadding(
1431        1, 0, 0, views::kUnrelatedControlVerticalSpacing);
1432    layout->AddView(remove_account_button_);
1433  } else {
1434    layout->AddPaddingRow(0, views::kUnrelatedControlVerticalSpacing);
1435  }
1436
1437  TitleCard* title_card = new TitleCard(IDS_PROFILES_ACCOUNT_REMOVAL_TITLE,
1438      this, &account_removal_cancel_button_);
1439  return TitleCard::AddPaddedTitleCard(view, title_card,
1440      kFixedAccountRemovalViewWidth);
1441}
1442
1443views::View* ProfileChooserView::CreateNewProfileManagementPreviewView() {
1444  return CreateTutorialView(
1445      profiles::TUTORIAL_MODE_ENABLE_PREVIEW,
1446      l10n_util::GetStringUTF16(IDS_PROFILES_PREVIEW_TUTORIAL_TITLE),
1447      l10n_util::GetStringUTF16(IDS_PROFILES_PREVIEW_TUTORIAL_CONTENT_TEXT),
1448      l10n_util::GetStringUTF16(IDS_PROFILES_PROFILE_TUTORIAL_LEARN_MORE),
1449      l10n_util::GetStringUTF16(IDS_PROFILES_TUTORIAL_TRY_BUTTON),
1450      &tutorial_learn_more_link_,
1451      &tutorial_enable_new_profile_management_button_);
1452}
1453
1454views::View* ProfileChooserView::CreateEndPreviewView() {
1455  views::View* view = new views::View();
1456  views::GridLayout* layout = CreateSingleColumnLayout(
1457      view, kFixedAccountRemovalViewWidth - 2 * views::kButtonHEdgeMarginNew);
1458  layout->SetInsets(0,
1459                    views::kButtonHEdgeMarginNew,
1460                    views::kButtonVEdgeMarginNew,
1461                    views::kButtonHEdgeMarginNew);
1462
1463  // Adds main text.
1464  views::Label* content_label = new views::Label(
1465      l10n_util::GetStringUTF16(IDS_PROFILES_END_PREVIEW_TEXT));
1466  content_label->SetMultiLine(true);
1467  content_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
1468  ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
1469  const gfx::FontList& small_font_list =
1470      rb->GetFontList(ui::ResourceBundle::SmallFont);
1471  content_label->SetFontList(small_font_list);
1472  layout->StartRowWithPadding(1, 0, 0, views::kUnrelatedControlVerticalSpacing);
1473  layout->AddView(content_label);
1474
1475  // Adds button.
1476  end_preview_and_relaunch_button_ = new views::BlueButton(
1477      this, l10n_util::GetStringUTF16(IDS_PROFILES_END_PREVIEW_AND_RELAUNCH));
1478  end_preview_and_relaunch_button_->SetHorizontalAlignment(
1479      gfx::ALIGN_CENTER);
1480  layout->StartRowWithPadding(
1481      1, 0, 0, views::kUnrelatedControlVerticalSpacing);
1482  layout->AddView(end_preview_and_relaunch_button_);
1483
1484  TitleCard* title_card = new TitleCard(
1485      IDS_PROFILES_END_PREVIEW, this, &end_preview_cancel_button_);
1486  return TitleCard::AddPaddedTitleCard(
1487      view, title_card, kFixedAccountRemovalViewWidth);
1488}
1489
1490