diff options
Diffstat (limited to 'chrome')
29 files changed, 626 insertions, 115 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', |