summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authornoms@chromium.org <noms@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-10-17 08:56:38 +0000
committernoms@chromium.org <noms@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-10-17 08:56:38 +0000
commitee4379ebef30d92167b756092d9535351be3f036 (patch)
treec63ed201b8527951f90aefdb0f1497b58aba5638
parent3fe8d2f86756a06a49ceff42cc32879e5e63117e (diff)
downloadchromium_src-ee4379ebef30d92167b756092d9535351be3f036.zip
chromium_src-ee4379ebef30d92167b756092d9535351be3f036.tar.gz
chromium_src-ee4379ebef30d92167b756092d9535351be3f036.tar.bz2
Redesign of the avatar menu button.
Screenshots: https://drive.google.com/folderview?id=0B1B1Up4p2NRMYm8zRzFhQkpCTUE&usp=sharing This is behind the --new-profile-management flag, and shows the avatar switcher as a menu button in the caption area. The button shows the user's name, rather than an image. There will be an upcoming CL to ensure that the correct button is displayed for Metro (Win8) browsers (this CL would display the Aero button for Win8 as well). BUG=287883 Committed: https://src.chromium.org/viewvc/chrome?view=rev&revision=228293 Review URL: https://codereview.chromium.org/24647003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@229082 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/app/generated_resources.grd4
-rw-r--r--chrome/app/theme/theme_resources.grd62
-rw-r--r--chrome/browser/profiles/profiles_state.cc26
-rw-r--r--chrome/browser/profiles/profiles_state.h6
-rw-r--r--chrome/browser/ui/view_ids.h1
-rw-r--r--chrome/browser/ui/views/avatar_menu_bubble_view.h1
-rw-r--r--chrome/browser/ui/views/avatar_menu_button_browsertest.cc89
-rw-r--r--chrome/browser/ui/views/frame/browser_frame.cc4
-rw-r--r--chrome/browser/ui/views/frame/browser_frame.h3
-rw-r--r--chrome/browser/ui/views/frame/browser_non_client_frame_view.cc47
-rw-r--r--chrome/browser/ui/views/frame/browser_non_client_frame_view.h18
-rw-r--r--chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc3
-rw-r--r--chrome/browser/ui/views/frame/browser_view.cc13
-rw-r--r--chrome/browser/ui/views/frame/browser_view.h12
-rw-r--r--chrome/browser/ui/views/frame/glass_browser_frame_view.cc75
-rw-r--r--chrome/browser/ui/views/frame/glass_browser_frame_view.h6
-rw-r--r--chrome/browser/ui/views/frame/opaque_browser_frame_view.cc25
-rw-r--r--chrome/browser/ui/views/frame/opaque_browser_frame_view.h2
-rw-r--r--chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.cc35
-rw-r--r--chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.h3
-rw-r--r--chrome/browser/ui/views/frame/opaque_browser_frame_view_layout_delegate.h3
-rw-r--r--chrome/browser/ui/views/frame/opaque_browser_frame_view_layout_unittest.cc35
-rw-r--r--chrome/browser/ui/views/new_avatar_button.cc96
-rw-r--r--chrome/browser/ui/views/new_avatar_button.h35
-rw-r--r--chrome/browser/ui/views/new_avatar_menu_button_browsertest.cc123
-rw-r--r--chrome/browser/ui/views/profile_chooser_view.cc4
-rw-r--r--chrome/browser/ui/views/profile_chooser_view.h5
-rw-r--r--chrome/chrome_browser_ui.gypi4
-rw-r--r--chrome/chrome_tests.gypi1
-rw-r--r--ui/views/controls/button/text_button.h1
30 files changed, 626 insertions, 116 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 621f534d..7aa78be 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -11270,6 +11270,10 @@ Would you like to start <ph name="CONTROL_PANEL_APPLET_NAME">$1<ex>Add/Remove Pr
<message name="IDS_NUMBERED_PROFILE_NAME" desc="The name given to a newly created profile. Displayed in wrench menu and settings UI.">
User <ph name="VALUE">$1<ex>1</ex></ph>
</message>
+ <message name="IDS_GUEST_PROFILE_NAME" desc="The name given to the guest
+ browsing profile. Displayed in the avatar menu bubble and button UI.">
+ Guest
+ </message>
<message name="IDS_DEFAULT_AVATAR_NAME_8" desc="The default name given to a newly created profile with the female spy avatar.">
Agent X
diff --git a/chrome/app/theme/theme_resources.grd b/chrome/app/theme/theme_resources.grd
index d50f1c5..10923dc 100644
--- a/chrome/app/theme/theme_resources.grd
+++ b/chrome/app/theme/theme_resources.grd
@@ -713,6 +713,68 @@
<structure type="chrome_scaled_image" name="IDR_PROFILE_AVATAR_24" file="profile_avatar_note.png" />
<structure type="chrome_scaled_image" name="IDR_PROFILE_AVATAR_25" file="profile_avatar_sun_cloud.png" />
</if>
+
+ <!-- New style avatar button -->
+ <!-- Windows, themed windows -->
+ <structure type="chrome_scaled_image" name="IDR_AVATAR_THEMED_BUTTON_DROPARROW" file="win/avatar_button/themed/sign_in_button_arrow.png" />
+ <structure type="chrome_scaled_image" name="IDR_AVATAR_THEMED_BUTTON_NORMAL_BOTTOM" file="win/avatar_button/themed/sign_in_button_bottom.png" />
+ <structure type="chrome_scaled_image" name="IDR_AVATAR_THEMED_BUTTON_NORMAL_BOTTOM_LEFT" file="win/avatar_button/themed/sign_in_button_bottom_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_AVATAR_THEMED_BUTTON_NORMAL_BOTTOM_RIGHT" file="win/avatar_button/themed/sign_in_button_bottom_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_AVATAR_THEMED_BUTTON_NORMAL_CENTER" file="win/avatar_button/themed/sign_in_button_center.png" />
+ <structure type="chrome_scaled_image" name="IDR_AVATAR_THEMED_BUTTON_NORMAL_LEFT" file="win/avatar_button/themed/sign_in_button_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_AVATAR_THEMED_BUTTON_NORMAL_RIGHT" file="win/avatar_button/themed/sign_in_button_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_AVATAR_THEMED_BUTTON_NORMAL_TOP" file="win/avatar_button/themed/sign_in_button_top.png" />
+ <structure type="chrome_scaled_image" name="IDR_AVATAR_THEMED_BUTTON_NORMAL_TOP_LEFT" file="win/avatar_button/themed/sign_in_button_top_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_AVATAR_THEMED_BUTTON_NORMAL_TOP_RIGHT" file="win/avatar_button/themed/sign_in_button_top_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_AVATAR_THEMED_BUTTON_HOVER_BOTTOM" file="win/avatar_button/themed/sign_in_button_hover_bottom.png" />
+ <structure type="chrome_scaled_image" name="IDR_AVATAR_THEMED_BUTTON_HOVER_BOTTOM_LEFT" file="win/avatar_button/themed/sign_in_button_hover_bottom_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_AVATAR_THEMED_BUTTON_HOVER_BOTTOM_RIGHT" file="win/avatar_button/themed/sign_in_button_hover_bottom_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_AVATAR_THEMED_BUTTON_HOVER_CENTER" file="win/avatar_button/themed/sign_in_button_hover_center.png" />
+ <structure type="chrome_scaled_image" name="IDR_AVATAR_THEMED_BUTTON_HOVER_LEFT" file="win/avatar_button/themed/sign_in_button_hover_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_AVATAR_THEMED_BUTTON_HOVER_RIGHT" file="win/avatar_button/themed/sign_in_button_hover_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_AVATAR_THEMED_BUTTON_HOVER_TOP" file="win/avatar_button/themed/sign_in_button_hover_top.png" />
+ <structure type="chrome_scaled_image" name="IDR_AVATAR_THEMED_BUTTON_HOVER_TOP_LEFT" file="win/avatar_button/themed/sign_in_button_hover_top_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_AVATAR_THEMED_BUTTON_HOVER_TOP_RIGHT" file="win/avatar_button/themed/sign_in_button_hover_top_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_AVATAR_THEMED_BUTTON_PRESSED_BOTTOM" file="win/avatar_button/themed/sign_in_button_pressed_bottom.png" />
+ <structure type="chrome_scaled_image" name="IDR_AVATAR_THEMED_BUTTON_PRESSED_BOTTOM_LEFT" file="win/avatar_button/themed/sign_in_button_pressed_bottom_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_AVATAR_THEMED_BUTTON_PRESSED_BOTTOM_RIGHT" file="win/avatar_button/themed/sign_in_button_pressed_bottom_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_AVATAR_THEMED_BUTTON_PRESSED_CENTER" file="win/avatar_button/themed/sign_in_button_pressed_center.png" />
+ <structure type="chrome_scaled_image" name="IDR_AVATAR_THEMED_BUTTON_PRESSED_LEFT" file="win/avatar_button/themed/sign_in_button_pressed_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_AVATAR_THEMED_BUTTON_PRESSED_RIGHT" file="win/avatar_button/themed/sign_in_button_pressed_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_AVATAR_THEMED_BUTTON_PRESSED_TOP" file="win/avatar_button/themed/sign_in_button_pressed_top.png" />
+ <structure type="chrome_scaled_image" name="IDR_AVATAR_THEMED_BUTTON_PRESSED_TOP_LEFT" file="win/avatar_button/themed/sign_in_button_pressed_top_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_AVATAR_THEMED_BUTTON_PRESSED_TOP_RIGHT" file="win/avatar_button/themed/sign_in_button_pressed_top_right.png" />
+
+ <!-- Windows, glass windows -->
+ <structure type="chrome_scaled_image" name="IDR_AVATAR_GLASS_BUTTON_DROPARROW" file="win/avatar_button/win7/sign_in_button_arrow.png" />
+ <structure type="chrome_scaled_image" name="IDR_AVATAR_GLASS_BUTTON_NORMAL_BOTTOM" file="win/avatar_button/win7/sign_in_button_bottom.png" />
+ <structure type="chrome_scaled_image" name="IDR_AVATAR_GLASS_BUTTON_NORMAL_BOTTOM_LEFT" file="win/avatar_button/win7/sign_in_button_bottom_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_AVATAR_GLASS_BUTTON_NORMAL_BOTTOM_RIGHT" file="win/avatar_button/win7/sign_in_button_bottom_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_AVATAR_GLASS_BUTTON_NORMAL_CENTER" file="win/avatar_button/win7/sign_in_button_center.png" />
+ <structure type="chrome_scaled_image" name="IDR_AVATAR_GLASS_BUTTON_NORMAL_LEFT" file="win/avatar_button/win7/sign_in_button_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_AVATAR_GLASS_BUTTON_NORMAL_RIGHT" file="win/avatar_button/win7/sign_in_button_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_AVATAR_GLASS_BUTTON_NORMAL_TOP" file="win/avatar_button/win7/sign_in_button_top.png" />
+ <structure type="chrome_scaled_image" name="IDR_AVATAR_GLASS_BUTTON_NORMAL_TOP_LEFT" file="win/avatar_button/win7/sign_in_button_top_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_AVATAR_GLASS_BUTTON_NORMAL_TOP_RIGHT" file="win/avatar_button/win7/sign_in_button_top_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_AVATAR_GLASS_BUTTON_HOVER_BOTTOM" file="win/avatar_button/win7/sign_in_button_hover_bottom.png" />
+ <structure type="chrome_scaled_image" name="IDR_AVATAR_GLASS_BUTTON_HOVER_BOTTOM_LEFT" file="win/avatar_button/win7/sign_in_button_hover_bottom_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_AVATAR_GLASS_BUTTON_HOVER_BOTTOM_RIGHT" file="win/avatar_button/win7/sign_in_button_hover_bottom_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_AVATAR_GLASS_BUTTON_HOVER_CENTER" file="win/avatar_button/win7/sign_in_button_hover_center.png" />
+ <structure type="chrome_scaled_image" name="IDR_AVATAR_GLASS_BUTTON_HOVER_LEFT" file="win/avatar_button/win7/sign_in_button_hover_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_AVATAR_GLASS_BUTTON_HOVER_RIGHT" file="win/avatar_button/win7/sign_in_button_hover_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_AVATAR_GLASS_BUTTON_HOVER_TOP" file="win/avatar_button/win7/sign_in_button_hover_top.png" />
+ <structure type="chrome_scaled_image" name="IDR_AVATAR_GLASS_BUTTON_HOVER_TOP_LEFT" file="win/avatar_button/win7/sign_in_button_hover_top_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_AVATAR_GLASS_BUTTON_HOVER_TOP_RIGHT" file="win/avatar_button/win7/sign_in_button_hover_top_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_AVATAR_GLASS_BUTTON_PRESSED_BOTTOM" file="win/avatar_button/win7/sign_in_button_pressed_bottom.png" />
+ <structure type="chrome_scaled_image" name="IDR_AVATAR_GLASS_BUTTON_PRESSED_BOTTOM_LEFT" file="win/avatar_button/win7/sign_in_button_pressed_bottom_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_AVATAR_GLASS_BUTTON_PRESSED_BOTTOM_RIGHT" file="win/avatar_button/win7/sign_in_button_pressed_bottom_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_AVATAR_GLASS_BUTTON_PRESSED_CENTER" file="win/avatar_button/win7/sign_in_button_pressed_center.png" />
+ <structure type="chrome_scaled_image" name="IDR_AVATAR_GLASS_BUTTON_PRESSED_LEFT" file="win/avatar_button/win7/sign_in_button_pressed_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_AVATAR_GLASS_BUTTON_PRESSED_RIGHT" file="win/avatar_button/win7/sign_in_button_pressed_right.png" />
+ <structure type="chrome_scaled_image" name="IDR_AVATAR_GLASS_BUTTON_PRESSED_TOP" file="win/avatar_button/win7/sign_in_button_pressed_top.png" />
+ <structure type="chrome_scaled_image" name="IDR_AVATAR_GLASS_BUTTON_PRESSED_TOP_LEFT" file="win/avatar_button/win7/sign_in_button_pressed_top_left.png" />
+ <structure type="chrome_scaled_image" name="IDR_AVATAR_GLASS_BUTTON_PRESSED_TOP_RIGHT" file="win/avatar_button/win7/sign_in_button_pressed_top_right.png" />
+
<if expr="pp_ifdef('chromeos')">
<structure type="chrome_scaled_image" name="IDR_PROFILE_PICTURE_LOADING" file="profile_loading.png" />
<structure type="chrome_scaled_image" name="IDR_RESET_WARNING" file="reset_warning.png" />
diff --git a/chrome/browser/profiles/profiles_state.cc b/chrome/browser/profiles/profiles_state.cc
index 72e1295..3165271 100644
--- a/chrome/browser/profiles/profiles_state.cc
+++ b/chrome/browser/profiles/profiles_state.cc
@@ -7,9 +7,16 @@
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/prefs/pref_registry_simple.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_info_cache.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/ui/browser.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
+#include "grit/generated_resources.h"
+#include "ui/base/l10n/l10n_util.h"
#if defined(OS_CHROMEOS)
#include "chrome/browser/chromeos/login/user_manager.h"
@@ -33,8 +40,7 @@ bool IsNewProfileManagementEnabled() {
switches::kNewProfileManagement);
}
-base::FilePath GetDefaultProfileDir(
- const base::FilePath& user_data_dir) {
+base::FilePath GetDefaultProfileDir(const base::FilePath& user_data_dir) {
base::FilePath default_profile_dir(user_data_dir);
default_profile_dir =
default_profile_dir.AppendASCII(chrome::kInitialProfile);
@@ -54,4 +60,20 @@ void RegisterPrefs(PrefRegistrySimple* registry) {
registry->RegisterListPref(prefs::kProfilesLastActive);
}
+string16 GetActiveProfileDisplayName(Browser* browser) {
+ string16 profile_name;
+ Profile* profile = browser->profile();
+
+ if (profile->IsGuestSession()) {
+ profile_name = l10n_util::GetStringUTF16(IDS_GUEST_PROFILE_NAME);
+ } else {
+ ProfileInfoCache& cache =
+ g_browser_process->profile_manager()->GetProfileInfoCache();
+ size_t index = cache.GetIndexOfProfileWithPath(profile->GetPath());
+ if (index != std::string::npos)
+ profile_name = cache.GetNameOfProfileAtIndex(index);
+ }
+ return profile_name;
+}
+
} // namespace profiles
diff --git a/chrome/browser/profiles/profiles_state.h b/chrome/browser/profiles/profiles_state.h
index 2858e62..3f6debc 100644
--- a/chrome/browser/profiles/profiles_state.h
+++ b/chrome/browser/profiles/profiles_state.h
@@ -5,6 +5,9 @@
#ifndef CHROME_BROWSER_PROFILES_PROFILES_STATE_H_
#define CHROME_BROWSER_PROFILES_PROFILES_STATE_H_
+#include "base/strings/string16.h"
+
+class Browser;
class PrefRegistrySimple;
namespace base { class FilePath; }
@@ -26,6 +29,9 @@ base::FilePath GetProfilePrefsPath(const base::FilePath& profile_dir);
// Register multi-profile related preferences in Local State.
void RegisterPrefs(PrefRegistrySimple* registry);
+// Returns the display name of the active on-the-record profile (or guest).
+string16 GetActiveProfileDisplayName(Browser* browser);
+
} // namespace profiles
#endif // CHROME_BROWSER_PROFILES_PROFILES_STATE_H_
diff --git a/chrome/browser/ui/view_ids.h b/chrome/browser/ui/view_ids.h
index 3d0fcb8..81e035e 100644
--- a/chrome/browser/ui/view_ids.h
+++ b/chrome/browser/ui/view_ids.h
@@ -24,6 +24,7 @@ enum ViewID {
VIEW_ID_WINDOW_TITLE,
VIEW_ID_AVATAR_LABEL,
VIEW_ID_AVATAR_BUTTON,
+ VIEW_ID_NEW_AVATAR_BUTTON,
// Tabs within a window/tab strip, counting from the left.
VIEW_ID_TAB_0,
diff --git a/chrome/browser/ui/views/avatar_menu_bubble_view.h b/chrome/browser/ui/views/avatar_menu_bubble_view.h
index 781e6be..e9e7225 100644
--- a/chrome/browser/ui/views/avatar_menu_bubble_view.h
+++ b/chrome/browser/ui/views/avatar_menu_bubble_view.h
@@ -131,7 +131,6 @@ class AvatarMenuBubbleView : public views::BubbleDelegateView,
bool expanded_;
DISALLOW_COPY_AND_ASSIGN(AvatarMenuBubbleView);
- FRIEND_TEST_ALL_PREFIXES(AvatarMenuButtonTest, SignOut);
};
#endif // CHROME_BROWSER_UI_VIEWS_AVATAR_MENU_BUBBLE_VIEW_H_
diff --git a/chrome/browser/ui/views/avatar_menu_button_browsertest.cc b/chrome/browser/ui/views/avatar_menu_button_browsertest.cc
index a3c0125..02f5cb3 100644
--- a/chrome/browser/ui/views/avatar_menu_button_browsertest.cc
+++ b/chrome/browser/ui/views/avatar_menu_button_browsertest.cc
@@ -7,35 +7,24 @@
#include "base/command_line.h"
#include "base/path_service.h"
#include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/profiles/avatar_menu.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/profiles/profiles_state.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/views/avatar_menu_bubble_view.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
-#include "chrome/browser/ui/views/profile_chooser_view.h"
-#include "chrome/browser/ui/views/user_manager_view.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/test_switches.h"
#include "chrome/test/base/testing_browser_process.h"
-#include "content/public/test/test_utils.h"
#include "grit/generated_resources.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/views/controls/button/label_button.h"
-class AvatarMenuButtonTest : public InProcessBrowserTest,
- public testing::WithParamInterface<bool> {
+class AvatarMenuButtonTest : public InProcessBrowserTest {
public:
AvatarMenuButtonTest();
virtual ~AvatarMenuButtonTest();
protected:
- virtual void SetUp() OVERRIDE;
-
- bool UsingNewProfileChooser();
void CreateTestingProfile();
AvatarMenuButton* GetAvatarMenuButton();
void StartAvatarMenu();
@@ -50,33 +39,10 @@ AvatarMenuButtonTest::AvatarMenuButtonTest() {
AvatarMenuButtonTest::~AvatarMenuButtonTest() {
}
-void AvatarMenuButtonTest::SetUp() {
- if (GetParam()) {
- if (!UsingNewProfileChooser()) {
- CommandLine::ForCurrentProcess()->AppendSwitch(
- switches::kNewProfileManagement);
- }
- DCHECK(UsingNewProfileChooser());
- } else {
- DCHECK(!UsingNewProfileChooser());
- }
-
- InProcessBrowserTest::SetUp();
-}
-
-bool AvatarMenuButtonTest::UsingNewProfileChooser() {
- return CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kNewProfileManagement);
-}
-
void AvatarMenuButtonTest::CreateTestingProfile() {
ProfileManager* profile_manager = g_browser_process->profile_manager();
EXPECT_EQ(1u, profile_manager->GetNumberOfProfiles());
- // Sign in the default profile
- ProfileInfoCache& cache = profile_manager->GetProfileInfoCache();
- cache.SetUserNameOfProfileAtIndex(0, UTF8ToUTF16("user_name"));
-
base::FilePath path;
PathService::Get(chrome::DIR_USER_DATA, &path);
path = path.AppendASCII("test_profile");
@@ -99,28 +65,25 @@ void AvatarMenuButtonTest::StartAvatarMenu() {
ASSERT_TRUE(button);
AvatarMenuBubbleView::set_close_on_deactivate(false);
- ProfileChooserView::set_close_on_deactivate(false);
static_cast<views::MenuButtonListener*>(button)->OnMenuButtonClicked(
NULL, gfx::Point());
base::MessageLoop::current()->RunUntilIdle();
- EXPECT_NE(AvatarMenuBubbleView::IsShowing(),
- ProfileChooserView::IsShowing());
+ EXPECT_TRUE(AvatarMenuBubbleView::IsShowing());
}
-IN_PROC_BROWSER_TEST_P(AvatarMenuButtonTest, HideOnSecondClick) {
+IN_PROC_BROWSER_TEST_F(AvatarMenuButtonTest, HideOnSecondClick) {
#if defined(OS_WIN) && defined(USE_ASH)
// Disable this test in Metro+Ash for now (http://crbug.com/262796).
if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
return;
#endif
- if (!profiles::IsMultipleProfilesEnabled() ||
- UsingNewProfileChooser()) {
+ // If multiprofile mode is not enabled, you can't switch between profiles.
+ if (!profiles::IsMultipleProfilesEnabled())
return;
- }
CreateTestingProfile();
- StartAvatarMenu();
+ ASSERT_NO_FATAL_FAILURE(StartAvatarMenu());
// Verify that clicking again doesn't reshow it.
AvatarMenuButton* button = GetAvatarMenuButton();
@@ -131,44 +94,4 @@ IN_PROC_BROWSER_TEST_P(AvatarMenuButtonTest, HideOnSecondClick) {
AvatarMenuBubbleView::Hide();
base::MessageLoop::current()->RunUntilIdle();
EXPECT_FALSE(AvatarMenuBubbleView::IsShowing());
- EXPECT_FALSE(ProfileChooserView::IsShowing());
-}
-
-IN_PROC_BROWSER_TEST_P(AvatarMenuButtonTest, NewSignOut) {
- if (!profiles::IsMultipleProfilesEnabled() ||
- !UsingNewProfileChooser()) {
- return;
- }
-
- CreateTestingProfile();
- StartAvatarMenu();
-
- BrowserList* browser_list =
- BrowserList::GetInstance(chrome::GetActiveDesktop());
- EXPECT_EQ(1U, browser_list->size());
- content::WindowedNotificationObserver window_close_observer(
- chrome::NOTIFICATION_BROWSER_CLOSED,
- content::Source<Browser>(browser()));
-
- AvatarMenu* menu =
- ProfileChooserView::profile_bubble_->avatar_menu_.get();
- const AvatarMenu::Item& menu_item_before =
- menu->GetItemAt(menu->GetActiveProfileIndex());
- EXPECT_FALSE(menu_item_before.signin_required);
-
- ui::MouseEvent mouse_ev(ui::ET_MOUSE_RELEASED, gfx::Point(), gfx::Point(), 0);
- menu->SetLogoutURL("about:blank");
-
- ProfileChooserView::profile_bubble_->LinkClicked(
- static_cast<views::Link*>(
- ProfileChooserView::profile_bubble_->signout_current_profile_link_),
- 0);
-
- EXPECT_TRUE(menu->GetItemAt(menu->GetActiveProfileIndex()).signin_required);
-
- window_close_observer.Wait(); // Rely on test timeout for failure indication.
- EXPECT_TRUE(browser_list->empty());
}
-
-INSTANTIATE_TEST_CASE_P(Old, AvatarMenuButtonTest, testing::Values(false));
-INSTANTIATE_TEST_CASE_P(New, AvatarMenuButtonTest, testing::Values(true));
diff --git a/chrome/browser/ui/views/frame/browser_frame.cc b/chrome/browser/ui/views/frame/browser_frame.cc
index 3c5fb8b..3788223 100644
--- a/chrome/browser/ui/views/frame/browser_frame.cc
+++ b/chrome/browser/ui/views/frame/browser_frame.cc
@@ -252,6 +252,10 @@ AvatarMenuButton* BrowserFrame::GetAvatarMenuButton() {
return browser_frame_view_->avatar_button();
}
+NewAvatarButton* BrowserFrame::GetNewAvatarMenuButton() {
+ return browser_frame_view_->new_avatar_button();
+}
+
#if !defined(OS_WIN) || defined(USE_AURA)
bool BrowserFrame::ShouldLeaveOffsetNearTopBorder() {
return !IsMaximized();
diff --git a/chrome/browser/ui/views/frame/browser_frame.h b/chrome/browser/ui/views/frame/browser_frame.h
index 023e143..3a2a852 100644
--- a/chrome/browser/ui/views/frame/browser_frame.h
+++ b/chrome/browser/ui/views/frame/browser_frame.h
@@ -16,6 +16,7 @@ class AvatarMenuButton;
class BrowserRootView;
class BrowserView;
class NativeBrowserFrame;
+class NewAvatarButton;
class NonClientFrameView;
class SystemMenuModelBuilder;
@@ -98,6 +99,8 @@ class BrowserFrame
AvatarMenuButton* GetAvatarMenuButton();
+ NewAvatarButton* GetNewAvatarMenuButton();
+
// Returns the menu model. BrowserFrame owns the returned model.
ui::MenuModel* GetSystemMenuModel();
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc
index 367aae1..d7f46d9 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc
@@ -9,11 +9,14 @@
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_info_cache.h"
#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/profiles/profiles_state.h"
#include "chrome/browser/ui/view_ids.h"
#include "chrome/browser/ui/views/avatar_label.h"
#include "chrome/browser/ui/views/avatar_menu_button.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/browser/ui/views/frame/taskbar_decorator.h"
+#include "chrome/browser/ui/views/new_avatar_button.h"
+#include "chrome/browser/ui/views/profile_chooser_view.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "third_party/skia/include/core/SkColor.h"
@@ -28,7 +31,8 @@ BrowserNonClientFrameView::BrowserNonClientFrameView(BrowserFrame* frame,
: frame_(frame),
browser_view_(browser_view),
avatar_button_(NULL),
- avatar_label_(NULL) {
+ avatar_label_(NULL),
+ new_avatar_button_(NULL) {
}
BrowserNonClientFrameView::~BrowserNonClientFrameView() {
@@ -41,7 +45,9 @@ void BrowserNonClientFrameView::VisibilityChanged(views::View* starting_from,
// The first time UpdateAvatarInfo() is called the window is not visible so
// DrawTaskBarDecoration() has no effect. Therefore we need to call it again
// once the window is visible.
- UpdateAvatarInfo();
+ if (!browser_view_->IsRegularOrGuestSession() ||
+ !profiles::IsNewProfileManagementEnabled())
+ UpdateAvatarInfo();
}
void BrowserNonClientFrameView::OnThemeChanged() {
@@ -59,8 +65,7 @@ void BrowserNonClientFrameView::UpdateAvatarInfo() {
AddChildView(avatar_label_);
}
avatar_button_ = new AvatarMenuButton(
- browser_view_->browser(),
- browser_view_->IsOffTheRecord() && !browser_view_->IsGuestSession());
+ browser_view_->browser(), !browser_view_->IsRegularOrGuestSession());
avatar_button_->set_id(VIEW_ID_AVATAR_BUTTON);
AddChildView(avatar_button_);
frame_->GetRootView()->Layout();
@@ -111,3 +116,37 @@ void BrowserNonClientFrameView::UpdateAvatarInfo() {
frame_->GetNativeWindow(),
AvatarMenu::ShouldShowAvatarMenu() ? &avatar : NULL);
}
+
+void BrowserNonClientFrameView::UpdateNewStyleAvatarInfo(
+ views::ButtonListener* listener,
+ const NewAvatarButton::AvatarButtonStyle style) {
+ DCHECK(profiles::IsNewProfileManagementEnabled());
+ // This should never be called in incognito mode.
+ DCHECK(browser_view_->IsRegularOrGuestSession());
+
+ if (browser_view_->ShouldShowAvatar()) {
+ if (!new_avatar_button_) {
+ string16 profile_name =
+ profiles::GetActiveProfileDisplayName(browser_view_->browser());
+ new_avatar_button_ = new NewAvatarButton(listener, profile_name, style);
+ new_avatar_button_->set_id(VIEW_ID_NEW_AVATAR_BUTTON);
+ AddChildView(new_avatar_button_);
+ frame_->GetRootView()->Layout();
+ }
+ } else if (new_avatar_button_) {
+ delete new_avatar_button_;
+ new_avatar_button_ = NULL;
+ frame_->GetRootView()->Layout();
+ }
+}
+
+void BrowserNonClientFrameView::ShowProfileChooserViewBubble() {
+ gfx::Point origin;
+ views::View::ConvertPointToScreen(new_avatar_button(), &origin);
+ gfx::Rect bounds(origin, size());
+
+ ProfileChooserView::ShowBubble(
+ new_avatar_button(), views::BubbleBorder::TOP_RIGHT,
+ views::BubbleBorder::ALIGN_EDGE_TO_ANCHOR_EDGE, bounds,
+ browser_view_->browser());
+}
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view.h b/chrome/browser/ui/views/frame/browser_non_client_frame_view.h
index 91a9b0d..681a06e 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view.h
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view.h
@@ -5,12 +5,14 @@
#ifndef CHROME_BROWSER_UI_VIEWS_FRAME_BROWSER_NON_CLIENT_FRAME_VIEW_H_
#define CHROME_BROWSER_UI_VIEWS_FRAME_BROWSER_NON_CLIENT_FRAME_VIEW_H_
+#include "chrome/browser/ui/views/new_avatar_button.h"
#include "ui/views/window/non_client_view.h"
class AvatarLabel;
class AvatarMenuButton;
class BrowserFrame;
class BrowserView;
+class NewAvatarButton;
// A specialization of the NonClientFrameView object that provides additional
// Browser-specific methods.
@@ -34,6 +36,8 @@ class BrowserNonClientFrameView : public views::NonClientFrameView {
AvatarMenuButton* avatar_button() const { return avatar_button_; }
+ NewAvatarButton* new_avatar_button() const { return new_avatar_button_; }
+
AvatarLabel* avatar_label() const { return avatar_label_; }
// Returns the bounds within which the TabStrip should be laid out.
@@ -62,6 +66,16 @@ class BrowserNonClientFrameView : public views::NonClientFrameView {
// Updates the title and icon of the avatar button.
void UpdateAvatarInfo();
+ // Updates the title of the avatar button displayed in the caption area.
+ // The button uses |style| to match the browser window style and notifies
+ // |listener| when it is clicked.
+ void UpdateNewStyleAvatarInfo(views::ButtonListener* listener,
+ const NewAvatarButton::AvatarButtonStyle style);
+
+ // Anchor and show the ProfileChooser bubble under the avatar button in
+ // the caption area.
+ void ShowProfileChooserViewBubble();
+
private:
// The frame that hosts this view.
BrowserFrame* frame_;
@@ -75,6 +89,10 @@ class BrowserNonClientFrameView : public views::NonClientFrameView {
// Avatar label that is used for a managed user.
AvatarLabel* avatar_label_;
+
+ // Menu button that displays the name of the active or guest profile.
+ // May be NULL and will not be displayed for off the record profiles.
+ NewAvatarButton* new_avatar_button_;
};
namespace chrome {
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc
index 22ef7d3..f9c577b 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc
@@ -531,8 +531,7 @@ void BrowserNonClientFrameViewAsh::PaintContentEdge(gfx::Canvas* canvas) {
}
int BrowserNonClientFrameViewAsh::GetThemeFrameImageId() const {
- bool is_incognito = browser_view()->IsOffTheRecord() &&
- !browser_view()->IsGuestSession();
+ bool is_incognito = !browser_view()->IsRegularOrGuestSession();
if (browser_view()->IsBrowserTypeNormal()) {
// Use the standard resource ids to allow users to theme the frames.
if (ShouldPaintAsActive()) {
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc
index b12feea..a7dd621 100644
--- a/chrome/browser/ui/views/frame/browser_view.cc
+++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -548,6 +548,15 @@ bool BrowserView::IsOffTheRecord() const {
return browser_->profile()->IsOffTheRecord();
}
+bool BrowserView::IsGuestSession() const {
+ return browser_->profile()->IsGuestSession();
+}
+
+bool BrowserView::IsRegularOrGuestSession() const {
+ Profile* profile = browser_->profile();
+ return (profile->IsGuestSession() || !profile->IsOffTheRecord());
+}
+
int BrowserView::GetOTRIconResourceID() const {
int otr_resource_id = IDR_OTR_ICON;
if (ui::GetDisplayLayout() == ui::LAYOUT_TOUCH) {
@@ -562,10 +571,6 @@ int BrowserView::GetOTRIconResourceID() const {
return otr_resource_id;
}
-bool BrowserView::IsGuestSession() const {
- return browser_->profile()->IsGuestSession();
-}
-
int BrowserView::GetGuestIconResourceID() const {
return IDR_GUEST_ICON;
}
diff --git a/chrome/browser/ui/views/frame/browser_view.h b/chrome/browser/ui/views/frame/browser_view.h
index 5e589b8..9991575 100644
--- a/chrome/browser/ui/views/frame/browser_view.h
+++ b/chrome/browser/ui/views/frame/browser_view.h
@@ -192,14 +192,18 @@ class BrowserView : public BrowserWindow,
// incognito.
bool IsOffTheRecord() const;
- // Returns the resource ID to use for the OTR icon, which depends on
- // which layout is being shown and whether we are full-screen.
- int GetOTRIconResourceID() const;
-
// Returns true if the profile associated with this Browser window is
// a guest session.
bool IsGuestSession() const;
+ // Returns true if the profile associated with this Browser window is
+ // not off the record or a guest session.
+ bool IsRegularOrGuestSession() const;
+
+ // Returns the resource ID to use for the OTR icon, which depends on
+ // which layout is being shown and whether we are full-screen.
+ int GetOTRIconResourceID() const;
+
// Returns the resource ID to use for the Guest icon, which may depend on
// which layout is being shown and whether we are full-screen.
int GetGuestIconResourceID() const;
diff --git a/chrome/browser/ui/views/frame/glass_browser_frame_view.cc b/chrome/browser/ui/views/frame/glass_browser_frame_view.cc
index b482292..6d70928 100644
--- a/chrome/browser/ui/views/frame/glass_browser_frame_view.cc
+++ b/chrome/browser/ui/views/frame/glass_browser_frame_view.cc
@@ -11,9 +11,11 @@
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profiles_state.h"
#include "chrome/browser/themes/theme_properties.h"
#include "chrome/browser/ui/views/avatar_menu_button.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
+#include "chrome/browser/ui/views/new_avatar_button.h"
#include "chrome/browser/ui/views/tabs/tab.h"
#include "chrome/browser/ui/views/tabs/tab_strip.h"
#include "chrome/browser/ui/views/toolbar_view.h"
@@ -55,6 +57,8 @@ const int kAvatarBottomSpacing = 2;
const int kAvatarLeftSpacing = 2;
// Space between the right edge of the avatar and the tabstrip.
const int kAvatarRightSpacing = -2;
+// How far the new avatar button is from the left of the minimize button.
+const int kNewAvatarButtonOffset = 5;
// The content left/right images have a shadow built into them.
const int kContentEdgeShadowThickness = 2;
// The top 3 px of the tabstrip is shadow; in maximized mode we push this off
@@ -85,7 +89,12 @@ GlassBrowserFrameView::GlassBrowserFrameView(BrowserFrame* frame,
if (browser_view->ShouldShowWindowIcon())
InitThrobberIcons();
- UpdateAvatarInfo();
+ if (browser_view->IsRegularOrGuestSession() &&
+ profiles::IsNewProfileManagementEnabled())
+ UpdateNewStyleAvatarInfo(this, NewAvatarButton::GLASS_BUTTON);
+ else
+ UpdateAvatarInfo();
+
if (!browser_view->IsOffTheRecord()) {
registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED,
content::NotificationService::AllSources());
@@ -102,6 +111,12 @@ gfx::Rect GlassBrowserFrameView::GetBoundsForTabStrip(
views::View* tabstrip) const {
int minimize_button_offset =
std::min(frame()->GetMinimizeButtonOffset(), width());
+
+ // The new avatar button is optionally displayed to the left of the
+ // minimize button.
+ if (browser_view()->ShouldShowAvatar() && new_avatar_button())
+ minimize_button_offset -= new_avatar_button()->width();
+
int tabstrip_x = browser_view()->ShouldShowAvatar() ?
(avatar_bounds_.right() + kAvatarRightSpacing) :
NonClientBorderThickness() + kTabStripIndent;
@@ -210,6 +225,10 @@ int GlassBrowserFrameView::NonClientHitTest(const gfx::Point& point) {
if (avatar_button() && avatar_button()->GetMirroredBounds().Contains(point))
return HTCLIENT;
+ if (new_avatar_button() &&
+ new_avatar_button()->GetMirroredBounds().Contains(point))
+ return HTCLIENT;
+
int frame_component = frame()->client_view()->NonClientHitTest(point);
// See if we're in the sysmenu region. We still have to check the tabstrip
@@ -244,14 +263,32 @@ void GlassBrowserFrameView::OnPaint(gfx::Canvas* canvas) {
}
void GlassBrowserFrameView::Layout() {
- LayoutAvatar();
+ if (browser_view()->ShouldShowAvatar()) {
+ if (browser_view()->IsRegularOrGuestSession() &&
+ profiles::IsNewProfileManagementEnabled())
+ LayoutNewStyleAvatar();
+ else
+ LayoutAvatar();
+ }
+
LayoutClientView();
}
bool GlassBrowserFrameView::HitTestRect(const gfx::Rect& rect) const {
- return (avatar_button() &&
- avatar_button()->GetMirroredBounds().Intersects(rect)) ||
- !frame()->client_view()->bounds().Intersects(rect);
+ bool hit_avatar_button = avatar_button() &&
+ avatar_button()->GetMirroredBounds().Intersects(rect);
+ bool hit_new_avatar_button = new_avatar_button() &&
+ new_avatar_button()->GetMirroredBounds().Intersects(rect);
+ return hit_avatar_button || hit_new_avatar_button ||
+ !frame()->client_view()->bounds().Intersects(rect);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// GlassBrowserFrameView, views::ButtonListener overrides:
+void GlassBrowserFrameView::ButtonPressed(views::Button* sender,
+ const ui::Event& event) {
+ if (sender == new_avatar_button())
+ ShowProfileChooserViewBubble();
}
///////////////////////////////////////////////////////////////////////////////
@@ -403,6 +440,28 @@ void GlassBrowserFrameView::PaintRestoredClientEdge(gfx::Canvas* canvas) {
toolbar_color);
}
+void GlassBrowserFrameView::LayoutNewStyleAvatar() {
+ if (!new_avatar_button())
+ return;
+
+ gfx::Size label_size = new_avatar_button()->GetPreferredSize();
+ int button_size_with_offset = kNewAvatarButtonOffset + label_size.width();
+
+ int button_x = frame()->GetMinimizeButtonOffset() -
+ kNewAvatarButtonOffset - label_size.width();
+
+ if (base::i18n::IsRTL())
+ button_x = width() - frame()->GetMinimizeButtonOffset() +
+ kNewAvatarButtonOffset;
+
+ int button_y = frame()->IsMaximized() ? NonClientTopBorderHeight(false) : 1;
+ new_avatar_button()->SetBounds(
+ button_x,
+ button_y,
+ label_size.width(),
+ button_y + gfx::win::GetSystemMetricsInDIP(SM_CXMENUSIZE));
+}
+
void GlassBrowserFrameView::LayoutAvatar() {
// Even though the avatar is used for both incognito and profiles we always
// use the incognito icon to layout the avatar button. The profile icon
@@ -504,7 +563,11 @@ void GlassBrowserFrameView::Observe(
const content::NotificationDetails& details) {
switch (type) {
case chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED:
- UpdateAvatarInfo();
+ if (browser_view()->IsRegularOrGuestSession() &&
+ profiles::IsNewProfileManagementEnabled())
+ UpdateNewStyleAvatarInfo(this, NewAvatarButton::GLASS_BUTTON);
+ else
+ UpdateAvatarInfo();
break;
default:
NOTREACHED() << "Got a notification we didn't register for!";
diff --git a/chrome/browser/ui/views/frame/glass_browser_frame_view.h b/chrome/browser/ui/views/frame/glass_browser_frame_view.h
index d872738..c9b2701c 100644
--- a/chrome/browser/ui/views/frame/glass_browser_frame_view.h
+++ b/chrome/browser/ui/views/frame/glass_browser_frame_view.h
@@ -16,6 +16,7 @@
class BrowserView;
class GlassBrowserFrameView : public BrowserNonClientFrameView,
+ public views::ButtonListener,
public content::NotificationObserver {
public:
// Constructs a non-client view for an BrowserFrame.
@@ -46,6 +47,10 @@ class GlassBrowserFrameView : public BrowserNonClientFrameView,
virtual void Layout() OVERRIDE;
virtual bool HitTestRect(const gfx::Rect& rect) const OVERRIDE;
+ // Overidden from views::ButtonListener:
+ virtual void ButtonPressed(views::Button* sender,
+ const ui::Event& event) OVERRIDE;
+
private:
// Returns the thickness of the border that makes up the window frame edges.
// This does not include any client edge.
@@ -66,6 +71,7 @@ class GlassBrowserFrameView : public BrowserNonClientFrameView,
// Layout various sub-components of this view.
void LayoutAvatar();
+ void LayoutNewStyleAvatar();
void LayoutClientView();
// Returns the insets of the client area.
diff --git a/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc b/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc
index fdfe4c7..4de7694c 100644
--- a/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc
+++ b/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc
@@ -12,6 +12,7 @@
#include "base/prefs/pref_service.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/profiles/profiles_state.h"
#include "chrome/browser/themes/theme_properties.h"
#include "chrome/browser/ui/views/avatar_label.h"
#include "chrome/browser/ui/views/avatar_menu_button.h"
@@ -19,6 +20,7 @@
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.h"
#include "chrome/browser/ui/views/frame/opaque_browser_frame_view_platform_specific.h"
+#include "chrome/browser/ui/views/new_avatar_button.h"
#include "chrome/browser/ui/views/tab_icon_view.h"
#include "chrome/browser/ui/views/tabs/tab_strip.h"
#include "chrome/browser/ui/views/toolbar_view.h"
@@ -150,7 +152,12 @@ OpaqueBrowserFrameView::OpaqueBrowserFrameView(BrowserFrame* frame,
window_title_->set_id(VIEW_ID_WINDOW_TITLE);
AddChildView(window_title_);
- UpdateAvatarInfo();
+ if (browser_view->IsRegularOrGuestSession() &&
+ profiles::IsNewProfileManagementEnabled())
+ UpdateNewStyleAvatarInfo(this, NewAvatarButton::THEMED_BUTTON);
+ else
+ UpdateAvatarInfo();
+
if (!browser_view->IsOffTheRecord()) {
registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED,
content::NotificationService::AllSources());
@@ -215,7 +222,9 @@ int OpaqueBrowserFrameView::NonClientHitTest(const gfx::Point& point) {
// label.
if ((avatar_button() &&
avatar_button()->GetMirroredBounds().Contains(point)) ||
- (avatar_label() && avatar_label()->GetMirroredBounds().Contains(point)))
+ (avatar_label() && avatar_label()->GetMirroredBounds().Contains(point)) ||
+ (new_avatar_button() &&
+ new_avatar_button()->GetMirroredBounds().Contains(point)))
return HTCLIENT;
int frame_component = frame()->client_view()->NonClientHitTest(point);
@@ -396,6 +405,8 @@ void OpaqueBrowserFrameView::ButtonPressed(views::Button* sender,
frame()->Restore();
else if (sender == close_button_)
frame()->Close();
+ else if (sender == new_avatar_button())
+ ShowProfileChooserViewBubble();
}
///////////////////////////////////////////////////////////////////////////////
@@ -427,7 +438,11 @@ void OpaqueBrowserFrameView::Observe(
const content::NotificationDetails& details) {
switch (type) {
case chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED:
- UpdateAvatarInfo();
+ if (browser_view() ->IsRegularOrGuestSession() &&
+ profiles::IsNewProfileManagementEnabled())
+ UpdateNewStyleAvatarInfo(this, NewAvatarButton::THEMED_BUTTON);
+ else
+ UpdateAvatarInfo();
break;
default:
NOTREACHED() << "Got a notification we didn't register for!";
@@ -477,6 +492,10 @@ bool OpaqueBrowserFrameView::ShouldShowAvatar() const {
return browser_view()->ShouldShowAvatar();
}
+bool OpaqueBrowserFrameView::IsRegularOrGuestSession() const {
+ return browser_view()->IsRegularOrGuestSession();
+}
+
gfx::ImageSkia OpaqueBrowserFrameView::GetOTRAvatarIcon() const {
return browser_view()->GetOTRAvatarIcon();
}
diff --git a/chrome/browser/ui/views/frame/opaque_browser_frame_view.h b/chrome/browser/ui/views/frame/opaque_browser_frame_view.h
index e732d01..1e9b018 100644
--- a/chrome/browser/ui/views/frame/opaque_browser_frame_view.h
+++ b/chrome/browser/ui/views/frame/opaque_browser_frame_view.h
@@ -20,6 +20,7 @@ class BrowserView;
class OpaqueBrowserFrameViewLayout;
class OpaqueBrowserFrameViewPlatformSpecific;
class TabIconView;
+class NewAvatarButton;
namespace views {
class ImageButton;
@@ -87,6 +88,7 @@ class OpaqueBrowserFrameView : public BrowserNonClientFrameView,
virtual bool ShouldLeaveOffsetNearTopBorder() const OVERRIDE;
virtual gfx::Size GetBrowserViewMinimumSize() const OVERRIDE;
virtual bool ShouldShowAvatar() const OVERRIDE;
+ virtual bool IsRegularOrGuestSession() const OVERRIDE;
virtual gfx::ImageSkia GetOTRAvatarIcon() const OVERRIDE;
virtual bool IsMaximized() const OVERRIDE;
virtual bool IsMinimized() const OVERRIDE;
diff --git a/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.cc b/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.cc
index c0848d8..071e392 100644
--- a/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.cc
+++ b/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.cc
@@ -4,6 +4,8 @@
#include "chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.h"
+#include "chrome/browser/profiles/profiles_state.h"
+#include "chrome/browser/ui/views/new_avatar_button.h"
#include "ui/gfx/font.h"
#include "ui/views/controls/button/image_button.h"
#include "ui/views/controls/label.h"
@@ -49,6 +51,9 @@ const int kAvatarLeftSpacing = 2;
// Space between the right edge of the avatar and the tabstrip.
const int kAvatarRightSpacing = -4;
+// How far the new avatar button is from the closest caption button.
+const int kNewAvatarButtonOffset = 5;
+
// In restored mode, the New Tab button isn't at the same height as the caption
// buttons, but the space will look cluttered if it actually slides under them,
// so we stop it when the gap between the two is down to 5 px.
@@ -101,7 +106,8 @@ OpaqueBrowserFrameViewLayout::OpaqueBrowserFrameViewLayout(
window_icon_(NULL),
window_title_(NULL),
avatar_label_(NULL),
- avatar_button_(NULL) {
+ avatar_button_(NULL),
+ new_avatar_button_(NULL) {
trailing_buttons_.push_back(views::FRAME_BUTTON_MINIMIZE);
trailing_buttons_.push_back(views::FRAME_BUTTON_MAXIMIZE);
trailing_buttons_.push_back(views::FRAME_BUTTON_CLOSE);
@@ -355,6 +361,24 @@ void OpaqueBrowserFrameViewLayout::LayoutTitleBar(views::View* host) {
}
}
+void OpaqueBrowserFrameViewLayout::LayoutNewStyleAvatar(views::View* host) {
+ gfx::Size label_size = new_avatar_button_->GetPreferredSize();
+ int button_size_with_offset = kNewAvatarButtonOffset + label_size.width();
+
+ int button_x = host->width() - trailing_button_start_ -
+ button_size_with_offset;
+ int button_y = CaptionButtonY(false);
+
+ trailing_button_start_ += button_size_with_offset;
+ minimum_size_for_buttons_ += button_size_with_offset;
+
+ new_avatar_button_->SetBounds(
+ button_x,
+ button_y,
+ label_size.width(),
+ button_y + kCaptionButtonHeightWithPadding);
+}
+
void OpaqueBrowserFrameViewLayout::LayoutAvatar() {
// Even though the avatar is used for both incognito and profiles we always
// use the incognito icon to layout the avatar button. The profile icon
@@ -567,6 +591,9 @@ void OpaqueBrowserFrameViewLayout::SetView(int id, views::View* view) {
case VIEW_ID_AVATAR_BUTTON:
avatar_button_ = view;
break;
+ case VIEW_ID_NEW_AVATAR_BUTTON:
+ new_avatar_button_ = static_cast<NewAvatarButton*>(view);
+ break;
default:
NOTIMPLEMENTED() << "Unknown view id " << id;
break;
@@ -593,7 +620,11 @@ void OpaqueBrowserFrameViewLayout::Layout(views::View* host) {
// on the trailing side.
leading_button_start_++;
- LayoutAvatar();
+ if (delegate_->IsRegularOrGuestSession() &&
+ profiles::IsNewProfileManagementEnabled())
+ LayoutNewStyleAvatar(host);
+ else
+ LayoutAvatar();
client_view_bounds_ = CalculateClientAreaBounds(
host->width(), host->height());
diff --git a/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.h b/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.h
index 12f6dea..b37bd51 100644
--- a/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.h
+++ b/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.h
@@ -9,6 +9,7 @@
#include "ui/views/layout/layout_manager.h"
#include "ui/views/window/frame_buttons.h"
+class NewAvatarButton;
class OpaqueBrowserFrameViewLayoutDelegate;
namespace views {
@@ -100,6 +101,7 @@ class OpaqueBrowserFrameViewLayout : public views::LayoutManager {
void LayoutWindowControls(views::View* host);
void LayoutTitleBar(views::View* host);
void LayoutAvatar();
+ void LayoutNewStyleAvatar(views::View* host);
void ConfigureButton(views::View* host,
views::FrameButton button_id,
@@ -167,6 +169,7 @@ class OpaqueBrowserFrameViewLayout : public views::LayoutManager {
views::View* avatar_label_;
views::View* avatar_button_;
+ NewAvatarButton* new_avatar_button_;
std::vector<views::FrameButton> leading_buttons_;
std::vector<views::FrameButton> trailing_buttons_;
diff --git a/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout_delegate.h b/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout_delegate.h
index 7858ed1..58709c8 100644
--- a/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout_delegate.h
+++ b/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout_delegate.h
@@ -35,6 +35,9 @@ class OpaqueBrowserFrameViewLayoutDelegate {
// Controls the visualization of the avatar
virtual bool ShouldShowAvatar() const = 0;
+ // Returns true if in guest mode or a non off the record session.
+ virtual bool IsRegularOrGuestSession() const = 0;
+
// We don't have a ThemeProvider in the layout manager, so plumb in the icon
// source here.
virtual gfx::ImageSkia GetOTRAvatarIcon() const = 0;
diff --git a/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout_unittest.cc b/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout_unittest.cc
index 5962fb0..c75f09a 100644
--- a/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout_unittest.cc
+++ b/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout_unittest.cc
@@ -5,9 +5,11 @@
#include "chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.h"
#include "base/basictypes.h"
+#include "base/command_line.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/ui/views/tab_icon_view.h"
#include "chrome/browser/ui/views/tabs/tab.h"
+#include "chrome/common/chrome_switches.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/image/image_skia_rep.h"
#include "ui/gfx/text_constants.h"
@@ -80,6 +82,10 @@ class TestLayoutDelegate : public OpaqueBrowserFrameViewLayoutDelegate {
return show_avatar_;
}
+ virtual bool IsRegularOrGuestSession() const OVERRIDE {
+ return true;
+ }
+
virtual gfx::ImageSkia GetOTRAvatarIcon() const OVERRIDE {
// The calculations depend on the size of the OTR resource, and chromeos
// uses a different sized image, so hard code the size of the current
@@ -213,6 +219,12 @@ class OpaqueBrowserFrameViewLayoutTest : public views::ViewsTestBase {
AddAvatarButton();
}
+ void AddNewAvatarButton() {
+ new_avatar_button_ = new views::MenuButton(NULL, string16(), NULL, false);
+ new_avatar_button_->set_id(VIEW_ID_NEW_AVATAR_BUTTON);
+ root_view_->AddChildView(new_avatar_button_);
+ }
+
void ExpectBasicWindowBounds() {
EXPECT_EQ("428,1 25x18", maximize_button_->bounds().ToString());
EXPECT_EQ("402,1 26x18", minimize_button_->bounds().ToString());
@@ -238,6 +250,7 @@ class OpaqueBrowserFrameViewLayoutTest : public views::ViewsTestBase {
views::MenuButton* menu_button_;
views::MenuButton* avatar_label_;
+ views::MenuButton* new_avatar_button_;
DISALLOW_COPY_AND_ASSIGN(OpaqueBrowserFrameViewLayoutTest);
};
@@ -314,6 +327,28 @@ TEST_F(OpaqueBrowserFrameViewLayoutTest, WindowWithAvatar) {
EXPECT_EQ("261x73", layout_manager_->GetMinimumSize(kWidth).ToString());
}
+
+TEST_F(OpaqueBrowserFrameViewLayoutTest, WindowWithNewAvatar) {
+ CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kNewProfileManagement);
+
+ // Tests a normal tabstrip window with the new style avatar icon.
+ AddNewAvatarButton();
+ root_view_->Layout();
+
+ ExpectBasicWindowBounds();
+
+ // Check the location of the caption button
+ EXPECT_EQ("385,1 12x20", new_avatar_button_->bounds().ToString());
+ // The basic window bounds are (-1, 13 398x29). There should not be an icon
+ // avatar in the left, and the new avatar button has an offset of 5 to its
+ // next control.
+ EXPECT_EQ("-1,13 381x29",
+ layout_manager_->GetBoundsForTabStrip(
+ delegate_->GetTabstripPreferredSize(), kWidth).ToString());
+ EXPECT_EQ("261x73", layout_manager_->GetMinimumSize(kWidth).ToString());
+}
+
TEST_F(OpaqueBrowserFrameViewLayoutTest, WindowWithAvatarLabelAndButton) {
AddAvatarLabel();
root_view_->Layout();
diff --git a/chrome/browser/ui/views/new_avatar_button.cc b/chrome/browser/ui/views/new_avatar_button.cc
new file mode 100644
index 0000000..9cf0d54
--- /dev/null
+++ b/chrome/browser/ui/views/new_avatar_button.cc
@@ -0,0 +1,96 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/views/new_avatar_button.h"
+
+#include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/color_utils.h"
+#include "ui/views/border.h"
+#include "ui/views/painter.h"
+
+namespace {
+
+// Text padding within the button border.
+const int kInset = 10;
+
+views::TextButtonDefaultBorder* CreateBorder(const int normal_image_set[],
+ const int hot_image_set[],
+ const int pushed_image_set[]) {
+ views::TextButtonDefaultBorder* border = new views::TextButtonDefaultBorder();
+
+ border->SetInsets(gfx::Insets(kInset, kInset, kInset, kInset));
+ border->set_normal_painter(
+ views::Painter::CreateImageGridPainter(normal_image_set));
+ border->set_hot_painter(
+ views::Painter::CreateImageGridPainter(hot_image_set));
+ border->set_pushed_painter(
+ views::Painter::CreateImageGridPainter(pushed_image_set));
+
+ return border;
+}
+
+} // namespace
+
+NewAvatarButton::NewAvatarButton(
+ views::ButtonListener* listener,
+ const string16& profile_name,
+ AvatarButtonStyle button_style)
+ : MenuButton(listener, profile_name, NULL, true) {
+ set_animate_on_state_change(false);
+
+ ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
+ SetFont(rb->GetFont(ui::ResourceBundle::BaseFont));
+
+ if (button_style == GLASS_BUTTON) {
+ const int kNormalImageSet[] = IMAGE_GRID(IDR_AVATAR_GLASS_BUTTON_NORMAL);
+ const int kHotImageSet[] = IMAGE_GRID(IDR_AVATAR_GLASS_BUTTON_HOVER);
+ const int kPushedImageSet[] = IMAGE_GRID(IDR_AVATAR_GLASS_BUTTON_PRESSED);
+
+ set_border(CreateBorder(kNormalImageSet, kHotImageSet, kPushedImageSet));
+ set_menu_marker(
+ rb->GetImageNamed(IDR_AVATAR_GLASS_BUTTON_DROPARROW).ToImageSkia());
+ } else {
+ const int kNormalImageSet[] = IMAGE_GRID(IDR_AVATAR_THEMED_BUTTON_NORMAL);
+ const int kHotImageSet[] = IMAGE_GRID(IDR_AVATAR_THEMED_BUTTON_HOVER);
+ const int kPushedImageSet[] = IMAGE_GRID(IDR_AVATAR_THEMED_BUTTON_PRESSED);
+
+ set_border(CreateBorder(kNormalImageSet, kHotImageSet, kPushedImageSet));
+ set_menu_marker(
+ rb->GetImageNamed(IDR_AVATAR_THEMED_BUTTON_DROPARROW).ToImageSkia());
+ }
+ SchedulePaint();
+}
+
+NewAvatarButton::~NewAvatarButton() {
+}
+
+void NewAvatarButton::OnPaint(gfx::Canvas* canvas) {
+ // From TextButton::PaintButton, draw everything but the text.
+ OnPaintBackground(canvas);
+ OnPaintBorder(canvas);
+ OnPaintFocusBorder(canvas);
+
+ gfx::Rect rect;
+ // In RTL languages the marker gets drawn leftmost, so account for its offset.
+ if (base::i18n::IsRTL())
+ rect = gfx::Rect(-kInset, 0, size().width(), size().height());
+ else
+ rect = gfx::Rect(kInset, 0, size().width(), size().height());
+ // TODO(noms): This should be DrawStringRectWithHalo but that function
+ // has a bug at the moment and incorrectly draws the background.
+ canvas->DrawStringRectWithFlags(
+ text(),
+ gfx::FontList(ui::ResourceBundle::GetSharedInstance().GetFont(
+ ui::ResourceBundle::BaseFont)),
+ SK_ColorBLACK,
+ rect,
+ gfx::Canvas::NO_SUBPIXEL_RENDERING);
+
+ // From MenuButton::PaintButton, paint the marker
+ PaintMenuMarker(canvas);
+}
diff --git a/chrome/browser/ui/views/new_avatar_button.h b/chrome/browser/ui/views/new_avatar_button.h
new file mode 100644
index 0000000..ad0d64a
--- /dev/null
+++ b/chrome/browser/ui/views/new_avatar_button.h
@@ -0,0 +1,35 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_VIEWS_NEW_AVATAR_BUTTON_H_
+#define CHROME_BROWSER_UI_VIEWS_NEW_AVATAR_BUTTON_H_
+
+#include "ui/views/controls/button/menu_button.h"
+
+// Avatar button that displays the active profile's name in the caption area.
+class NewAvatarButton : public views::MenuButton {
+ public:
+ // Different button styles that can be applied.
+ enum AvatarButtonStyle {
+ THEMED_BUTTON, // Used in a themed browser window.
+ GLASS_BUTTON, // Used in a native aero window.
+ METRO_BUTTON // Used in a metro window.
+ };
+
+ NewAvatarButton(views::ButtonListener* listener,
+ const string16& profile_name,
+ AvatarButtonStyle button_style);
+ virtual ~NewAvatarButton();
+
+ // views::View:
+ virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
+
+ private:
+ friend class NewAvatarMenuButtonTest;
+ FRIEND_TEST_ALL_PREFIXES(NewAvatarMenuButtonTest, SignOut);
+
+ DISALLOW_COPY_AND_ASSIGN(NewAvatarButton);
+};
+
+#endif // CHROME_BROWSER_UI_VIEWS_NEW_AVATAR_BUTTON_H_
diff --git a/chrome/browser/ui/views/new_avatar_menu_button_browsertest.cc b/chrome/browser/ui/views/new_avatar_menu_button_browsertest.cc
new file mode 100644
index 0000000..c4b21df
--- /dev/null
+++ b/chrome/browser/ui/views/new_avatar_menu_button_browsertest.cc
@@ -0,0 +1,123 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/command_line.h"
+#include "base/path_service.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/profiles/profiles_state.h"
+#include "chrome/browser/ui/browser_list.h"
+#include "chrome/browser/ui/views/avatar_menu_button.h"
+#include "chrome/browser/ui/views/frame/browser_view.h"
+#include "chrome/browser/ui/views/new_avatar_button.h"
+#include "chrome/browser/ui/views/profile_chooser_view.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/test_switches.h"
+#include "chrome/test/base/testing_browser_process.h"
+#include "content/public/test/test_utils.h"
+#include "grit/generated_resources.h"
+
+class NewAvatarMenuButtonTest : public InProcessBrowserTest {
+ public:
+ NewAvatarMenuButtonTest();
+ virtual ~NewAvatarMenuButtonTest();
+
+ protected:
+ virtual void SetUp() OVERRIDE;
+ virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE;
+ void CreateTestingProfile();
+ void StartAvatarMenu();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(NewAvatarMenuButtonTest);
+};
+
+NewAvatarMenuButtonTest::NewAvatarMenuButtonTest() {
+}
+
+NewAvatarMenuButtonTest::~NewAvatarMenuButtonTest() {
+}
+
+void NewAvatarMenuButtonTest::SetUp() {
+ InProcessBrowserTest::SetUp();
+ DCHECK(CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kNewProfileManagement));
+}
+
+void NewAvatarMenuButtonTest::SetUpCommandLine(CommandLine* command_line) {
+ command_line->AppendSwitch(switches::kNewProfileManagement);
+}
+
+void NewAvatarMenuButtonTest::CreateTestingProfile() {
+ ProfileManager* profile_manager = g_browser_process->profile_manager();
+ EXPECT_EQ(1u, profile_manager->GetNumberOfProfiles());
+
+ // Sign in the default profile
+ ProfileInfoCache& cache = profile_manager->GetProfileInfoCache();
+ cache.SetUserNameOfProfileAtIndex(0, UTF8ToUTF16("user_name"));
+
+ base::FilePath path;
+ PathService::Get(chrome::DIR_USER_DATA, &path);
+ path = path.AppendASCII("test_profile");
+ if (!base::PathExists(path))
+ ASSERT_TRUE(file_util::CreateDirectory(path));
+ Profile* profile =
+ Profile::CreateProfile(path, NULL, Profile::CREATE_MODE_SYNCHRONOUS);
+ profile_manager->RegisterTestingProfile(profile, true, false);
+ EXPECT_EQ(2u, profile_manager->GetNumberOfProfiles());
+}
+
+void NewAvatarMenuButtonTest::StartAvatarMenu() {
+ BrowserView* browser_view = reinterpret_cast<BrowserView*>(
+ browser()->window());
+
+ // Ensure that the avatar icon button is not also showing.
+ NewAvatarButton* button = browser_view->frame()->GetNewAvatarMenuButton();
+ ASSERT_TRUE(button);
+ ASSERT_FALSE(browser_view->frame()->GetAvatarMenuButton());
+
+ ProfileChooserView::set_close_on_deactivate(false);
+ ui::MouseEvent mouse_ev(ui::ET_MOUSE_RELEASED, gfx::Point(), gfx::Point(), 0);
+ button->NotifyClick(mouse_ev);
+ base::MessageLoop::current()->RunUntilIdle();
+ EXPECT_TRUE(ProfileChooserView::IsShowing());
+}
+
+IN_PROC_BROWSER_TEST_F(NewAvatarMenuButtonTest, SignOut) {
+ // If multiprofile mode is not enabled, you can't switch between profiles.
+ if (!profiles::IsMultipleProfilesEnabled())
+ return;
+
+ CreateTestingProfile();
+ ASSERT_NO_FATAL_FAILURE(StartAvatarMenu());
+
+ BrowserList* browser_list =
+ BrowserList::GetInstance(chrome::GetActiveDesktop());
+ EXPECT_EQ(1U, browser_list->size());
+ content::WindowedNotificationObserver window_close_observer(
+ chrome::NOTIFICATION_BROWSER_CLOSED,
+ content::Source<Browser>(browser()));
+
+ AvatarMenu* menu =
+ ProfileChooserView::profile_bubble_->avatar_menu_.get();
+ const AvatarMenu::Item& menu_item_before =
+ menu->GetItemAt(menu->GetActiveProfileIndex());
+ EXPECT_FALSE(menu_item_before.signin_required);
+
+ ui::MouseEvent mouse_ev(ui::ET_MOUSE_RELEASED, gfx::Point(), gfx::Point(), 0);
+ menu->SetLogoutURL("about:blank");
+
+ ProfileChooserView::profile_bubble_->LinkClicked(
+ static_cast<views::Link*>(
+ ProfileChooserView::profile_bubble_->signout_current_profile_link_),
+ 0);
+
+ EXPECT_TRUE(menu->GetItemAt(menu->GetActiveProfileIndex()).signin_required);
+
+ window_close_observer.Wait(); // Rely on test timeout for failure indication.
+ EXPECT_TRUE(browser_list->empty());
+}
diff --git a/chrome/browser/ui/views/profile_chooser_view.cc b/chrome/browser/ui/views/profile_chooser_view.cc
index 8518378..ca25cc2 100644
--- a/chrome/browser/ui/views/profile_chooser_view.cc
+++ b/chrome/browser/ui/views/profile_chooser_view.cc
@@ -48,6 +48,7 @@ const int kLargeImageSide = 64;
const int kSmallImageSide = 32;
const int kMinMenuWidth = 250;
const int kButtonHeight = 29;
+const int kArrowHeight = 10;
// Current profile avatar image.
views::View* CreateProfileImageView(const gfx::Image& icon) {
@@ -199,6 +200,7 @@ void ProfileChooserView::ShowBubble(
profile_bubble_->set_close_on_deactivate(close_on_deactivate_);
profile_bubble_->SetAlignment(border_alignment);
profile_bubble_->GetWidget()->Show();
+ profile_bubble_->SetArrowPaintType(views::BubbleBorder::PAINT_NONE);
}
// static
@@ -220,6 +222,8 @@ ProfileChooserView::ProfileChooserView(views::View* anchor_view,
browser_(browser) {
// Reset the default margins inherited from the BubbleDelegateView.
set_margins(gfx::Insets());
+ // Compensate for built-in vertical padding in the anchor view's image.
+ set_anchor_view_insets(gfx::Insets(kArrowHeight, 0, kArrowHeight, 0));
ResetLinksAndButtons();
diff --git a/chrome/browser/ui/views/profile_chooser_view.h b/chrome/browser/ui/views/profile_chooser_view.h
index eec7f2e..8affea1 100644
--- a/chrome/browser/ui/views/profile_chooser_view.h
+++ b/chrome/browser/ui/views/profile_chooser_view.h
@@ -55,9 +55,8 @@ class ProfileChooserView : public views::BubbleDelegateView,
}
private:
- friend class AvatarMenuButtonTest;
- FRIEND_TEST_ALL_PREFIXES(AvatarMenuButtonTest, NewSignOut);
- FRIEND_TEST_ALL_PREFIXES(AvatarMenuButtonTest, LaunchUserManagerScreen);
+ friend class NewAvatarMenuButtonTest;
+ FRIEND_TEST_ALL_PREFIXES(NewAvatarMenuButtonTest, SignOut);
typedef std::vector<size_t> Indexes;
typedef std::map<views::Button*, int> ButtonIndexes;
diff --git a/chrome/chrome_browser_ui.gypi b/chrome/chrome_browser_ui.gypi
index 5fdfbdd..301547c 100644
--- a/chrome/chrome_browser_ui.gypi
+++ b/chrome/chrome_browser_ui.gypi
@@ -1618,7 +1618,7 @@
'browser/ui/views/avatar_menu_button.cc',
'browser/ui/views/avatar_menu_button.h',
'browser/ui/views/avatar_label.cc',
- 'browser/ui/views/avatar_label.cc',
+ 'browser/ui/views/avatar_label.h',
'browser/ui/views/bookmarks/bookmark_bar_instructions_view.cc',
'browser/ui/views/bookmarks/bookmark_bar_instructions_view.h',
'browser/ui/views/bookmarks/bookmark_bar_view.cc',
@@ -1907,6 +1907,8 @@
'browser/ui/views/native_focus_tracker_views.h',
'browser/ui/views/native_focus_tracker_views_aura.cc',
'browser/ui/views/native_focus_tracker_views_win.cc',
+ 'browser/ui/views/new_avatar_button.cc',
+ 'browser/ui/views/new_avatar_button.h',
'browser/ui/views/notifications/balloon_collection_views.cc',
'browser/ui/views/notifications/balloon_view_host.cc',
'browser/ui/views/notifications/balloon_view_host.h',
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index 5d382f6..42ab87e 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -1404,6 +1404,7 @@
'browser/ui/views/frame/browser_view_browsertest.cc',
'browser/ui/views/frame/immersive_mode_controller_ash_browsertest.cc',
'browser/ui/views/location_bar/zoom_bubble_view_browsertest.cc',
+ 'browser/ui/views/new_avatar_menu_button_browsertest.cc',
'browser/ui/views/select_file_dialog_extension_browsertest.cc',
'browser/ui/views/toolbar_view_browsertest.cc',
'browser/ui/views/web_dialog_view_browsertest.cc',
diff --git a/ui/views/controls/button/text_button.h b/ui/views/controls/button/text_button.h
index 5dccaa2..9d9f86c 100644
--- a/ui/views/controls/button/text_button.h
+++ b/ui/views/controls/button/text_button.h
@@ -65,7 +65,6 @@ class VIEWS_EXPORT TextButtonDefaultBorder : public TextButtonBorder {
TextButtonDefaultBorder();
virtual ~TextButtonDefaultBorder();
- protected:
// TextButtonDefaultBorder takes and retains ownership of these |painter|s.
void set_normal_painter(Painter* painter) { normal_painter_.reset(painter); }
void set_hot_painter(Painter* painter) { hot_painter_.reset(painter); }