diff options
-rw-r--r-- | chrome/app/generated_resources.grd | 15 | ||||
-rw-r--r-- | chrome/browser/profiles/avatar_menu_model.cc | 84 | ||||
-rw-r--r-- | chrome/browser/profiles/avatar_menu_model.h | 15 | ||||
-rw-r--r-- | chrome/browser/profiles/avatar_menu_model_browsertest.cc | 47 | ||||
-rw-r--r-- | chrome/browser/profiles/profile_info_cache.cc | 18 | ||||
-rw-r--r-- | chrome/browser/profiles/profile_info_cache.h | 2 | ||||
-rw-r--r-- | chrome/browser/profiles/profile_info_interface.h | 3 | ||||
-rw-r--r-- | chrome/browser/profiles/profile_manager.h | 5 | ||||
-rw-r--r-- | chrome/browser/ui/views/avatar_menu_bubble_view.cc | 139 | ||||
-rw-r--r-- | chrome/browser/ui/views/avatar_menu_bubble_view.h | 8 | ||||
-rw-r--r-- | chrome/browser/ui/webui/sync_promo/sync_promo_ui.cc | 19 | ||||
-rw-r--r-- | chrome/browser/ui/webui/sync_promo/sync_promo_ui.h | 3 | ||||
-rw-r--r-- | chrome/chrome_tests.gypi | 1 | ||||
-rw-r--r-- | chrome/common/chrome_switches.cc | 4 | ||||
-rw-r--r-- | chrome/common/chrome_switches.h | 1 | ||||
-rw-r--r-- | google_apis/gaia/gaia_urls.cc | 6 | ||||
-rw-r--r-- | google_apis/gaia/gaia_urls.h | 2 |
17 files changed, 341 insertions, 31 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 5d9d78a..0fcf1b7 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd @@ -11577,6 +11577,21 @@ experiment id: "<ph name="EXPERIMENT_ID">$5<ex>ar1</ex></ph>" <message name="IDS_PROFILES_CREATE_NEW_PROFILE_LINK" desc="Link in the avatar menu bubble view to create a new profile."> New user </message> + <message name="IDS_PROFILES_MANAGE_PROFILES_BUTTON" desc="Button in the avatar menu bubble view to manage profiles."> + Manage + </message> + <message name="IDS_PROFILES_MANAGE_PROFILES_BUTTON_TIP" desc="Tool-tip text shown for button in the avatar menu bubble view to manage profiles."> + Create, change, or delete profiles. + </message> + <message name="IDS_PROFILES_PROFILE_SIGNOUT_BUTTON" desc="Button in the avatar menu bubble view to sign-out the current profile."> + Sign-out + </message> + <message name="IDS_PROFILES_PROFILE_SIGNOUT_BUTTON_TIP" desc="Tool-tip text shown for button in the avatar menu bubble view to sign-out the current profile."> + Sign-out user <ph name="PROFILE_USERNAME">$1<ex>user@gmail.com</ex></ph>. + </message> + <message name="IDS_PROFILES_PROFILE_SIGNOUT_BUTTON_TIP_UNAVAILABLE" desc="Tool-tip text shown for button in the avatar menu bubble view to sign-out the current profile when that button is not available because the profile has not been signed-in."> + Sign-out is possible only when signed in. + </message> <message name="IDS_PROFILES_EDIT_PROFILE_LINK" desc="Link in the avatar menu bubble to edit a profile."> edit </message> diff --git a/chrome/browser/profiles/avatar_menu_model.cc b/chrome/browser/profiles/avatar_menu_model.cc index 151acf9..5a29121 100644 --- a/chrome/browser/profiles/avatar_menu_model.cc +++ b/chrome/browser/profiles/avatar_menu_model.cc @@ -26,6 +26,8 @@ #include "chrome/common/url_constants.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/notification_service.h" +#include "content/public/browser/site_instance.h" +#include "google_apis/gaia/gaia_urls.h" #include "grit/generated_resources.h" #include "ui/base/l10n/l10n_util.h" @@ -58,6 +60,47 @@ void OnProfileCreated(bool always_create, const char kShowProfileSwitcherFieldTrialName[] = "ShowProfileSwitcher"; const char kAlwaysShowSwitcherGroupName[] = "AlwaysShow"; + +class SignoutTracker : public content::WebContentsObserver { + public: + SignoutTracker(Profile* profile, const GURL& signout_landing_url, + content::WebContents* contents); + + virtual void WebContentsDestroyed(content::WebContents* contents) OVERRIDE; + virtual void DidStopLoading(content::RenderViewHost* render_view_host) + OVERRIDE; + + private: + scoped_ptr<content::WebContents> contents_; + GURL signout_landing_url_; + Profile* profile_; + + DISALLOW_COPY_AND_ASSIGN(SignoutTracker); +}; + + +SignoutTracker::SignoutTracker(Profile* profile, + const GURL& signout_landing_url, + content::WebContents* contents) + : WebContentsObserver(contents), + contents_(contents), + signout_landing_url_(signout_landing_url), + profile_(profile) { +} + +void SignoutTracker::DidStopLoading(content::RenderViewHost* render_view_host) { + // Only close when we reach the final landing; ignore redirects until then. + if (web_contents()->GetURL() == signout_landing_url_) { + Observe(NULL); + BrowserList::CloseAllBrowsersWithProfile(profile_); + delete this; /* success */ + } +} + +void SignoutTracker::WebContentsDestroyed(content::WebContents* contents) { + delete this; /* failure */ +} + } // namespace AvatarMenuModel::AvatarMenuModel(ProfileInfoInterface* profile_cache, @@ -85,6 +128,7 @@ AvatarMenuModel::Item::Item(size_t model_index, const gfx::Image& icon) : icon(icon), active(false), signed_in(false), + signin_required(false), model_index(model_index) { } @@ -139,6 +183,11 @@ void AvatarMenuModel::AddNewProfile(ProfileMetrics::ProfileAdd type) { ProfileMetrics::LogProfileAddNewUser(type); } +base::FilePath AvatarMenuModel::GetProfilePath(size_t index) { + const Item& item = GetItemAt(index); + return profile_info_->GetPathOfProfileAtIndex(item.model_index); +} + size_t AvatarMenuModel::GetNumberOfItems() { return items_.size(); } @@ -227,6 +276,7 @@ void AvatarMenuModel::RebuildMenu() { base::FilePath path = profile_info_->GetPathOfProfileAtIndex(i); item->active = browser_->profile()->GetPath() == path; } + item->signin_required = profile_info_->ProfileIsSigninRequiredAtIndex(i); items_.push_back(item); } } @@ -234,3 +284,37 @@ void AvatarMenuModel::RebuildMenu() { void AvatarMenuModel::ClearMenu() { STLDeleteElements(&items_); } + + +content::WebContents* AvatarMenuModel::BeginSignOut( + const char* logout_override) { + ProfileManager* profile_manager = g_browser_process->profile_manager(); + Profile* current_profile = browser_->profile(); + + ProfileInfoCache& cache = profile_manager->GetProfileInfoCache(); + size_t index = cache.GetIndexOfProfileWithPath(current_profile->GetPath()); + cache.SetProfileSigninRequiredAtIndex(index, true); + + std::string landing_url = SyncPromoUI::GetSyncLandingURL("close", 1); + GURL logout_url(GaiaUrls::GetInstance()->service_logout_url() + + "?continue=" + landing_url); + if (logout_override) { + // We're testing... + landing_url = logout_override; + logout_url = GURL(logout_override); + } + + content::WebContents::CreateParams create_params(current_profile); + create_params.site_instance = + content::SiteInstance::CreateForURL(current_profile, logout_url); + content::WebContents* contents = content::WebContents::Create(create_params); + contents->GetController().LoadURL( + logout_url, content::Referrer(), + content::PAGE_TRANSITION_GENERATED, std::string()); + + // This object may be destructed when the menu closes but we need something + // around to finish the sign-out process and close the profile windows. + new SignoutTracker(current_profile, GURL(landing_url), contents); + + return contents; // returned for testing purposes +} diff --git a/chrome/browser/profiles/avatar_menu_model.h b/chrome/browser/profiles/avatar_menu_model.h index 308a825..e83af90 100644 --- a/chrome/browser/profiles/avatar_menu_model.h +++ b/chrome/browser/profiles/avatar_menu_model.h @@ -13,10 +13,13 @@ #include "chrome/browser/profiles/profile_metrics.h" #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h" +#include "content/public/browser/web_contents.h" +#include "content/public/browser/web_contents_observer.h" #include "ui/gfx/image/image.h" class AvatarMenuModelObserver; class Browser; +class Profile; class ProfileInfoInterface; // This class is the model for the menu-like interface that appears when the @@ -46,6 +49,9 @@ class AvatarMenuModel : public content::NotificationObserver { // expected to be the email of the signed in user. bool signed_in; + // Whether or not the current profile requires sign-in before use. + bool signin_required; + // The index in the |profile_cache| that this Item represents. size_t model_index; }; @@ -69,6 +75,9 @@ class AvatarMenuModel : public content::NotificationObserver { // Creates a new profile. void AddNewProfile(ProfileMetrics::ProfileAdd type); + // Gets the path associated with the profile at |index|. + base::FilePath GetProfilePath(size_t index); + // Gets the number of profiles. size_t GetNumberOfItems(); @@ -93,6 +102,12 @@ class AvatarMenuModel : public content::NotificationObserver { // True if avatar menu should be displayed. static bool ShouldShowAvatarMenu(); + // Start the sign-out process for this profile. + // Parameter |logout_override| alows changing the destination URL for the + // sign-out process and return value (the WebContents executing the sign-out) + // are for testing; pass NULL for normal use. + content::WebContents* BeginSignOut(const char* logout_override); + private: // Rebuilds the menu from the cache and notifies the |observer_|. void RebuildMenu(); diff --git a/chrome/browser/profiles/avatar_menu_model_browsertest.cc b/chrome/browser/profiles/avatar_menu_model_browsertest.cc new file mode 100644 index 0000000..970a660 --- /dev/null +++ b/chrome/browser/profiles/avatar_menu_model_browsertest.cc @@ -0,0 +1,47 @@ +// Copyright (c) 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/profiles/avatar_menu_model.h" + +#include "base/path_service.h" +#include "chrome/browser/profiles/profile_manager.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/browser_list.h" +#include "chrome/common/chrome_notification_types.h" +#include "chrome/common/chrome_paths.h" +#include "chrome/test/base/in_process_browser_test.h" +#include "chrome/test/base/testing_browser_process.h" +#include "content/public/test/test_utils.h" + +namespace { + +typedef InProcessBrowserTest AvatarMenuModelTest; + +IN_PROC_BROWSER_TEST_F(AvatarMenuModelTest, SignOut) { + if (!ProfileManager::IsMultipleProfilesEnabled()) + return; + + ProfileManager* profile_manager = g_browser_process->profile_manager(); + Profile* current_profile = browser()->profile(); + ProfileInfoCache& cache = profile_manager->GetProfileInfoCache(); + size_t index = cache.GetIndexOfProfileWithPath(current_profile->GetPath()); + + AvatarMenuModel model(&cache, NULL, browser()); + + BrowserList* browser_list = + BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_NATIVE); + EXPECT_EQ(1U, browser_list->size()); + content::WindowedNotificationObserver window_close_observer( + chrome::NOTIFICATION_BROWSER_CLOSED, + content::Source<Browser>(browser())); + + EXPECT_FALSE(cache.ProfileIsSigninRequiredAtIndex(index)); + model.BeginSignOut("about:blank"); + EXPECT_TRUE(cache.ProfileIsSigninRequiredAtIndex(index)); + + window_close_observer.Wait(); // rely on test time-out for failure indication + EXPECT_EQ(0U, browser_list->size()); +} + +} // namespace diff --git a/chrome/browser/profiles/profile_info_cache.cc b/chrome/browser/profiles/profile_info_cache.cc index 8b62ecd..b3409fd 100644 --- a/chrome/browser/profiles/profile_info_cache.cc +++ b/chrome/browser/profiles/profile_info_cache.cc @@ -48,6 +48,7 @@ const char kBackgroundAppsKey[] = "background_apps"; const char kHasMigratedToGAIAInfoKey[] = "has_migrated_to_gaia_info"; const char kGAIAPictureFileNameKey[] = "gaia_picture_file_name"; const char kIsManagedKey[] = "is_managed"; +const char kSigninRequiredKey[] = "signin_required"; const char kDefaultUrlPrefix[] = "chrome://theme/IDR_PROFILE_AVATAR_"; const char kGAIAPictureFileName[] = "Google Profile Picture.png"; @@ -373,6 +374,12 @@ bool ProfileInfoCache::ProfileIsManagedAtIndex(size_t index) const { return value; } +bool ProfileInfoCache::ProfileIsSigninRequiredAtIndex(size_t index) const { + bool value = false; + GetInfoForProfileAtIndex(index)->GetBoolean(kSigninRequiredKey, &value); + return value; +} + void ProfileInfoCache::OnGAIAPictureLoaded(const base::FilePath& path, gfx::Image** image) const { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); @@ -606,6 +613,17 @@ void ProfileInfoCache::SetIsUsingGAIAPictureOfProfileAtIndex(size_t index, OnProfileAvatarChanged(profile_path)); } +void ProfileInfoCache::SetProfileSigninRequiredAtIndex(size_t index, + bool value) { + if (value == ProfileIsSigninRequiredAtIndex(index)) + return; + + scoped_ptr<DictionaryValue> info(GetInfoForProfileAtIndex(index)->DeepCopy()); + info->SetBoolean(kSigninRequiredKey, value); + // This takes ownership of |info|. + SetInfoForProfileAtIndex(index, info.release()); +} + string16 ProfileInfoCache::ChooseNameForNewProfile(size_t icon_index) const { string16 name; for (int name_index = 1; ; ++name_index) { diff --git a/chrome/browser/profiles/profile_info_cache.h b/chrome/browser/profiles/profile_info_cache.h index 82545fd..cd71118 100644 --- a/chrome/browser/profiles/profile_info_cache.h +++ b/chrome/browser/profiles/profile_info_cache.h @@ -75,6 +75,7 @@ class ProfileInfoCache : public ProfileInfoInterface, virtual bool IsUsingGAIAPictureOfProfileAtIndex( size_t index) const OVERRIDE; virtual bool ProfileIsManagedAtIndex(size_t index) const OVERRIDE; + virtual bool ProfileIsSigninRequiredAtIndex(size_t index) const OVERRIDE; size_t GetAvatarIconIndexOfProfileAtIndex(size_t index) const; @@ -88,6 +89,7 @@ class ProfileInfoCache : public ProfileInfoInterface, void SetIsUsingGAIANameOfProfileAtIndex(size_t index, bool value); void SetGAIAPictureOfProfileAtIndex(size_t index, const gfx::Image* image); void SetIsUsingGAIAPictureOfProfileAtIndex(size_t index, bool value); + void SetProfileSigninRequiredAtIndex(size_t index, bool value); // Returns unique name that can be assigned to a newly created profile. string16 ChooseNameForNewProfile(size_t icon_index) const; diff --git a/chrome/browser/profiles/profile_info_interface.h b/chrome/browser/profiles/profile_info_interface.h index 4e3ed99..40d423d 100644 --- a/chrome/browser/profiles/profile_info_interface.h +++ b/chrome/browser/profiles/profile_info_interface.h @@ -51,6 +51,9 @@ class ProfileInfoInterface { virtual bool ProfileIsManagedAtIndex(size_t index) const = 0; + // This profile is associated with an account but has been signed-out. + virtual bool ProfileIsSigninRequiredAtIndex(size_t index) const = 0; + protected: virtual ~ProfileInfoInterface() {} }; diff --git a/chrome/browser/profiles/profile_manager.h b/chrome/browser/profiles/profile_manager.h index a73ee96..05babfa 100644 --- a/chrome/browser/profiles/profile_manager.h +++ b/chrome/browser/profiles/profile_manager.h @@ -211,7 +211,10 @@ class ProfileManager : public base::NonThreadSafe, // Autoloads profiles if they are running background apps. void AutoloadProfiles(); - // Registers and adds testing profile to the ProfileManager. + // Sign-Out a profile against use until re-authentication. + void SignOutProfile(Profile* profile); + + // Register and add testing profile to the ProfileManager. Use ONLY in tests. // This allows the creation of Profiles outside of the standard creation path // for testing. If |addToCache|, adds to ProfileInfoCache as well. // If |start_deferred_task_runners|, starts the deferred task runners. diff --git a/chrome/browser/ui/views/avatar_menu_bubble_view.cc b/chrome/browser/ui/views/avatar_menu_bubble_view.cc index 2505c62..3a861eb 100644 --- a/chrome/browser/ui/views/avatar_menu_bubble_view.cc +++ b/chrome/browser/ui/views/avatar_menu_bubble_view.cc @@ -6,6 +6,8 @@ #include <algorithm> +#include "base/command_line.h" +#include "base/string16.h" #include "base/utf_string_conversions.h" #include "chrome/app/chrome_command_ids.h" #include "chrome/browser/browser_process.h" @@ -13,8 +15,17 @@ #include "chrome/browser/profiles/profile_info_cache.h" #include "chrome/browser/profiles/profile_info_util.h" #include "chrome/browser/profiles/profile_manager.h" +#include "chrome/browser/signin/signin_manager.h" +#include "chrome/browser/signin/signin_manager_factory.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_commands.h" +#include "chrome/browser/ui/browser_list.h" +#include "chrome/browser/ui/browser_window.h" +#include "chrome/browser/ui/chrome_pages.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/common/url_constants.h" +#include "content/public/browser/page_navigator.h" +#include "content/public/browser/web_contents.h" #include "grit/generated_resources.h" #include "grit/theme_resources.h" #include "ui/base/l10n/l10n_util.h" @@ -24,10 +35,12 @@ #include "ui/gfx/image/image.h" #include "ui/views/controls/button/custom_button.h" #include "ui/views/controls/button/image_button.h" +#include "ui/views/controls/button/label_button.h" #include "ui/views/controls/image_view.h" #include "ui/views/controls/label.h" #include "ui/views/controls/link.h" #include "ui/views/controls/separator.h" +#include "ui/views/layout/grid_layout.h" #include "ui/views/widget/widget.h" namespace { @@ -219,7 +232,7 @@ class ProfileItemView : public views::CustomButton, EditProfileLink* edit_link() { return edit_link_; } private: - static gfx::ImageSkia GetBadgedIcon(const gfx::ImageSkia& icon); + gfx::ImageSkia GetBadgedIcon(const gfx::ImageSkia& icon); bool IsHighlighted(); @@ -242,7 +255,7 @@ ProfileItemView::ProfileItemView(const AvatarMenuModel::Item& item, image_view_ = new ProfileImageView(); gfx::ImageSkia profile_icon = *item_.icon.ToImageSkia(); - if (item_.active) + if (item_.active || item_.signin_required) image_view_->SetImage(GetBadgedIcon(profile_icon)); else image_view_->SetImage(profile_icon); @@ -366,8 +379,15 @@ void ProfileItemView::OnFocusStateChanged(bool has_focus) { // static gfx::ImageSkia ProfileItemView::GetBadgedIcon(const gfx::ImageSkia& icon) { ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); - const gfx::ImageSkia* badge = rb.GetImageNamed( - IDR_PROFILE_SELECTED).ToImageSkia(); + const gfx::ImageSkia* badge = NULL; + + if (item_.active) + badge = rb.GetImageSkiaNamed(IDR_PROFILE_SELECTED); + else if (item_.signin_required) // TODO(bcwhite): create new icon + badge = rb.GetImageSkiaNamed(IDR_OMNIBOX_HTTPS_VALID); + else + NOTREACHED(); // function should only be called if one of above is true + gfx::Size icon_size = GetCenteredAndScaledRect(icon.width(), icon.height(), 0, 0, profiles::kAvatarIconWidth, kItemHeight).size(); gfx::CanvasImageSource* source = @@ -386,6 +406,67 @@ bool ProfileItemView::IsHighlighted() { } +// ActionButtonView ----------------------------------------------------------- + +// A custom view that manages the "action" buttons at the bottom of the list +// of profiles. +class ActionButtonView : public views::View { + public: + ActionButtonView(views::ButtonListener* listener, Profile* profile); + + private: + views::LabelButton* manage_button_; + views::LabelButton* signout_button_; + + DISALLOW_COPY_AND_ASSIGN(ActionButtonView); +}; + + +ActionButtonView::ActionButtonView(views::ButtonListener* listener, + Profile* profile) + : manage_button_(NULL), + signout_button_(NULL) { + std::string username; + SigninManagerBase* signin = + SigninManagerFactory::GetForProfile(profile); + if (signin != NULL) + username = signin->GetAuthenticatedUsername(); + + manage_button_ = new views::LabelButton( + listener, l10n_util::GetStringUTF16(IDS_PROFILES_MANAGE_PROFILES_BUTTON)); + manage_button_->SetStyle(views::Button::STYLE_NATIVE_TEXTBUTTON); + manage_button_->SetTooltipText( + l10n_util::GetStringUTF16(IDS_PROFILES_MANAGE_PROFILES_BUTTON_TIP)); + manage_button_->set_tag(IDS_PROFILES_MANAGE_PROFILES_BUTTON); + + signout_button_ = new views::LabelButton( + listener, l10n_util::GetStringUTF16(IDS_PROFILES_PROFILE_SIGNOUT_BUTTON)); + signout_button_->SetStyle(views::Button::STYLE_NATIVE_TEXTBUTTON); + if (username.empty()) { + signout_button_->SetTooltipText( + l10n_util::GetStringUTF16( + IDS_PROFILES_PROFILE_SIGNOUT_BUTTON_TIP_UNAVAILABLE)); + signout_button_->SetEnabled(false); + } else { + signout_button_->SetTooltipText( + l10n_util::GetStringFUTF16(IDS_PROFILES_PROFILE_SIGNOUT_BUTTON_TIP, + UTF8ToUTF16(username))); + } + signout_button_->set_tag(IDS_PROFILES_PROFILE_SIGNOUT_BUTTON); + + views::GridLayout* layout = new views::GridLayout(this); + views::ColumnSet* columns = layout->AddColumnSet(0); + columns->AddColumn(views::GridLayout::LEADING, views::GridLayout::FILL, 1, + views::GridLayout::USE_PREF, 0, 0); + columns->AddColumn(views::GridLayout::TRAILING, views::GridLayout::FILL, 1, + views::GridLayout::USE_PREF, 0, 0); + layout->StartRow(0, 0); + layout->AddView(signout_button_); + layout->AddView(manage_button_); + SetLayoutManager(layout); +} + + // AvatarMenuBubbleView ------------------------------------------------------- // static @@ -430,7 +511,7 @@ AvatarMenuBubbleView::AvatarMenuBubbleView( anchor_rect_(anchor_rect), browser_(browser), separator_(NULL), - add_profile_link_(NULL) { + buttons_view_(NULL) { avatar_menu_model_.reset(new AvatarMenuModel( &g_browser_process->profile_manager()->GetProfileInfoCache(), this, browser_)); @@ -448,14 +529,13 @@ gfx::Size AvatarMenuBubbleView::GetPreferredSize() { total_height += size.height() + kItemMarginY; } - if (add_profile_link_) { + if (buttons_view_) { total_height += kSeparatorPaddingY * 2 + separator_->GetPreferredSize().height(); - gfx::Size add_profile_size = add_profile_link_->GetPreferredSize(); - max_width = std::max(max_width, - add_profile_size.width() + profiles::kAvatarIconWidth + kIconMarginX); - total_height += add_profile_link_->GetPreferredSize().height(); + gfx::Size buttons_size = buttons_view_->GetPreferredSize(); + max_width = std::max(max_width, buttons_size.width()); + total_height += buttons_size.height(); } const int kBubbleViewMaxWidth = 800; @@ -475,14 +555,14 @@ void AvatarMenuBubbleView::Layout() { y += item_height + kItemMarginY; } - if (add_profile_link_) { + if (buttons_view_) { y += kSeparatorPaddingY; int separator_height = separator_->GetPreferredSize().height(); separator_->SetBounds(0, y, width(), separator_height); y += kSeparatorPaddingY + separator_height; - add_profile_link_->SetBounds(profiles::kAvatarIconWidth + kIconMarginX, y, - width(), add_profile_link_->GetPreferredSize().height()); + buttons_view_->SetBounds(0, y, + width(), buttons_view_->GetPreferredSize().height()); } } @@ -517,6 +597,15 @@ bool AvatarMenuBubbleView::AcceleratorPressed( void AvatarMenuBubbleView::ButtonPressed(views::Button* sender, const ui::Event& event) { + if (sender->tag() == IDS_PROFILES_MANAGE_PROFILES_BUTTON) { + std::string subpage = chrome::kSearchUsersSubPage; + chrome::ShowSettingsSubPage(browser_, subpage); + return; + } else if (sender->tag() == IDS_PROFILES_PROFILE_SIGNOUT_BUTTON) { + avatar_menu_model_->BeginSignOut(NULL); + return; + } + for (size_t i = 0; i < item_views_.size(); ++i) { ProfileItemView* item_view = item_views_[i]; if (sender == item_view) { @@ -531,7 +620,7 @@ void AvatarMenuBubbleView::ButtonPressed(views::Button* sender, } void AvatarMenuBubbleView::LinkClicked(views::Link* source, int event_flags) { - if (source == add_profile_link_) { + if (source == buttons_view_) { avatar_menu_model_->AddNewProfile(ProfileMetrics::ADD_NEW_USER_ICON); return; } @@ -565,7 +654,7 @@ void AvatarMenuBubbleView::OnAvatarMenuModelChanged( AvatarMenuModel* avatar_menu_model) { // Unset all our child view references and call RemoveAllChildViews() which // will actually delete them. - add_profile_link_ = NULL; + buttons_view_ = NULL; item_views_.clear(); RemoveAllChildViews(true); @@ -579,16 +668,22 @@ void AvatarMenuBubbleView::OnAvatarMenuModelChanged( item_views_.push_back(item_view); } - if (avatar_menu_model_->ShouldShowAddNewProfileLink()) { + if (CommandLine::ForCurrentProcess()->HasSwitch( + switches::kNewProfileManagement)) { separator_ = new views::Separator(); AddChildView(separator_); - - add_profile_link_ = new views::Link( + buttons_view_ = new ActionButtonView(this, browser_->profile()); + AddChildView(buttons_view_); + } else if (avatar_menu_model_->ShouldShowAddNewProfileLink()) { + views::Link* add_profile_link = new views::Link( l10n_util::GetStringUTF16(IDS_PROFILES_CREATE_NEW_PROFILE_LINK)); - add_profile_link_->set_listener(this); - add_profile_link_->SetHorizontalAlignment(gfx::ALIGN_LEFT); - add_profile_link_->SetBackgroundColor(color()); - AddChildView(add_profile_link_); + add_profile_link->set_listener(this); + add_profile_link->SetHorizontalAlignment(gfx::ALIGN_CENTER); + add_profile_link->SetBackgroundColor(color()); + separator_ = new views::Separator(); + AddChildView(separator_); + buttons_view_ = add_profile_link; + AddChildView(buttons_view_); } // If the bubble has already been shown then resize and reposition the bubble. diff --git a/chrome/browser/ui/views/avatar_menu_bubble_view.h b/chrome/browser/ui/views/avatar_menu_bubble_view.h index ae2d284..6036c1e 100644 --- a/chrome/browser/ui/views/avatar_menu_bubble_view.h +++ b/chrome/browser/ui/views/avatar_menu_bubble_view.h @@ -9,6 +9,7 @@ #include "base/basictypes.h" #include "base/compiler_specific.h" +#include "base/gtest_prod_util.h" #include "chrome/browser/profiles/avatar_menu_model_observer.h" #include "ui/views/bubble/bubble_delegate.h" #include "ui/views/controls/button/button.h" @@ -18,6 +19,10 @@ class AvatarMenuModel; class Browser; class ProfileItemView; +namespace content { +class WebContents; +} + namespace views { class CustomButton; class Link; @@ -92,11 +97,12 @@ class AvatarMenuBubbleView : public views::BubbleDelegateView, // avatar_menu_model_->ShouldShowAddNewProfileLink() returns true. See // OnAvatarMenuModelChanged(). views::Separator* separator_; - views::Link* add_profile_link_; + views::View* buttons_view_; static AvatarMenuBubbleView* avatar_bubble_; 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/webui/sync_promo/sync_promo_ui.cc b/chrome/browser/ui/webui/sync_promo/sync_promo_ui.cc index 8f9f468..de6ae01 100644 --- a/chrome/browser/ui/webui/sync_promo/sync_promo_ui.cc +++ b/chrome/browser/ui/webui/sync_promo/sync_promo_ui.cc @@ -56,7 +56,7 @@ const char kSyncPromoQueryKeySource[] = "source"; // Gaia cannot support about:blank as a continue URL, so using a hosted blank // page instead. -const char kContinueUrlPrefix[] = +const char kSyncLandingUrlPrefix[] = "https://www.google.com/intl/%s/chrome/blank.html"; // The maximum number of times we want to show the sync promo at startup. @@ -219,6 +219,14 @@ void SyncPromoUI::SetUserSkippedSyncPromo(Profile* profile) { } // static +std::string SyncPromoUI::GetSyncLandingURL(const char* option, int value) { + const std::string& locale = g_browser_process->GetApplicationLocale(); + std::string url = base::StringPrintf(kSyncLandingUrlPrefix, locale.c_str()); + base::StringAppendF(&url, "?%s=%d", option, value); + return url; +} + +// static GURL SyncPromoUI::GetSyncPromoURL(const GURL& next_page, Source source, bool auto_close) { @@ -242,11 +250,8 @@ GURL SyncPromoUI::GetSyncPromoURL(const GURL& next_page, url_string = GaiaUrls::GetInstance()->service_login_url(); url_string.append("?service=chromiumsync&sarp=1"); - const std::string& locale = g_browser_process->GetApplicationLocale(); - std::string continue_url = base::StringPrintf(kContinueUrlPrefix, - locale.c_str()); - base::StringAppendF(&continue_url, "?%s=%d", kSyncPromoQueryKeySource, - static_cast<int>(source)); + std::string continue_url = GetSyncLandingURL( + kSyncPromoQueryKeySource, static_cast<int>(source)); base::StringAppendF(&url_string, "&%s=%s", kSyncPromoQueryKeyContinue, net::EscapeQueryParamValue( @@ -321,7 +326,7 @@ bool SyncPromoUI::IsContinueUrlForWebBasedSigninFlow(const GURL& url) { replacements.ClearQuery(); const std::string& locale = g_browser_process->GetApplicationLocale(); return url.ReplaceComponents(replacements) == - GURL(base::StringPrintf(kContinueUrlPrefix, locale.c_str())); + GURL(base::StringPrintf(kSyncLandingUrlPrefix, locale.c_str())); } // static diff --git a/chrome/browser/ui/webui/sync_promo/sync_promo_ui.h b/chrome/browser/ui/webui/sync_promo/sync_promo_ui.h index 829ec11..2dc281f 100644 --- a/chrome/browser/ui/webui/sync_promo/sync_promo_ui.h +++ b/chrome/browser/ui/webui/sync_promo/sync_promo_ui.h @@ -52,6 +52,9 @@ class SyncPromoUI : public content::WebUIController { // Registers the preferences the Sync Promo UI needs. static void RegisterUserPrefs(PrefRegistrySyncable* registry); + // Gets the sync landing page URL. + static std::string GetSyncLandingURL(const char* option, int value); + // Returns the sync promo URL wth the given arguments in the query. // |next_page| is the URL to navigate to when the user completes or skips the // promo. If an empty URL is given then the promo will navigate to the NTP. diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index afae846..32597bb 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -1457,6 +1457,7 @@ 'browser/printing/print_preview_dialog_controller_browsertest.cc', 'browser/printing/printing_layout_browsertest.cc', 'browser/process_singleton_browsertest.cc', + 'browser/profiles/avatar_menu_model_browsertest.cc', 'browser/profiles/profile_browsertest.cc', 'browser/profiles/profile_manager_browsertest.cc', 'browser/referrer_policy_browsertest.cc', diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc index 89842e0..86ed6d8 100644 --- a/chrome/common/chrome_switches.cc +++ b/chrome/common/chrome_switches.cc @@ -929,6 +929,10 @@ const char kNativeMessagingHosts[] = "native-messaging-hosts"; // Intended primarily for use with --log-net-log. const char kNetLogLevel[] = "net-log-level"; +// Use new profile management system, including profile sign-out and new +// choosers. +const char kNewProfileManagement[] = "new-profile-management"; + // Disables the default browser check. Useful for UI/browser tests where we // want to avoid having the default browser info-bar displayed. const char kNoDefaultBrowserCheck[] = "no-default-browser-check"; diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h index 9f441de..e0dbca6 100644 --- a/chrome/common/chrome_switches.h +++ b/chrome/common/chrome_switches.h @@ -250,6 +250,7 @@ extern const char kNaClLoaderCmdPrefix[]; extern const char kNaClLoaderProcess[]; extern const char kNativeMessagingHosts[]; extern const char kNetLogLevel[]; +extern const char kNewProfileManagement[]; extern const char kNoDefaultBrowserCheck[]; extern const char kNoDisplayingInsecureContent[]; extern const char kNoEvents[]; diff --git a/google_apis/gaia/gaia_urls.cc b/google_apis/gaia/gaia_urls.cc index f11ba89..543bd88 100644 --- a/google_apis/gaia/gaia_urls.cc +++ b/google_apis/gaia/gaia_urls.cc @@ -18,6 +18,7 @@ const char kCaptchaUrlPrefixSuffix[] = "/"; // API calls from accounts.google.com const char kClientLoginUrlSuffix[] = "/ClientLogin"; const char kServiceLoginUrlSuffix[] = "/ServiceLogin"; +const char kServiceLogoutUrlSuffix[] = "/Logout"; const char kIssueAuthTokenUrlSuffix[] = "/IssueAuthToken"; const char kGetUserInfoUrlSuffix[] = "/GetUserInfo"; const char kTokenAuthUrlSuffix[] = "/TokenAuth"; @@ -100,6 +101,7 @@ GaiaUrls::GaiaUrls() { gaia_login_form_realm_ = gaia_url_base + "/"; client_login_url_ = gaia_url_base + kClientLoginUrlSuffix; service_login_url_ = gaia_url_base + kServiceLoginUrlSuffix; + service_logout_url_ = gaia_url_base + kServiceLogoutUrlSuffix; issue_auth_token_url_ = gaia_url_base + kIssueAuthTokenUrlSuffix; get_user_info_url_ = gaia_url_base + kGetUserInfoUrlSuffix; token_auth_url_ = gaia_url_base + kTokenAuthUrlSuffix; @@ -164,6 +166,10 @@ const std::string& GaiaUrls::service_login_url() { return service_login_url_; } +const std::string& GaiaUrls::service_logout_url() { + return service_logout_url_; +} + const std::string& GaiaUrls::issue_auth_token_url() { return issue_auth_token_url_; } diff --git a/google_apis/gaia/gaia_urls.h b/google_apis/gaia/gaia_urls.h index 7bdfcfb..5a5cb11 100644 --- a/google_apis/gaia/gaia_urls.h +++ b/google_apis/gaia/gaia_urls.h @@ -20,6 +20,7 @@ class GaiaUrls { const std::string& gaia_origin_url(); const std::string& client_login_url(); const std::string& service_login_url(); + const std::string& service_logout_url(); const std::string& issue_auth_token_url(); const std::string& get_user_info_url(); const std::string& token_auth_url(); @@ -57,6 +58,7 @@ class GaiaUrls { std::string google_apis_origin_url_; std::string client_login_url_; std::string service_login_url_; + std::string service_logout_url_; std::string issue_auth_token_url_; std::string get_user_info_url_; std::string token_auth_url_; |