summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/app/generated_resources.grd15
-rw-r--r--chrome/browser/profiles/avatar_menu_model.cc84
-rw-r--r--chrome/browser/profiles/avatar_menu_model.h15
-rw-r--r--chrome/browser/profiles/avatar_menu_model_browsertest.cc47
-rw-r--r--chrome/browser/profiles/profile_info_cache.cc18
-rw-r--r--chrome/browser/profiles/profile_info_cache.h2
-rw-r--r--chrome/browser/profiles/profile_info_interface.h3
-rw-r--r--chrome/browser/profiles/profile_manager.h5
-rw-r--r--chrome/browser/ui/views/avatar_menu_bubble_view.cc139
-rw-r--r--chrome/browser/ui/views/avatar_menu_bubble_view.h8
-rw-r--r--chrome/browser/ui/webui/sync_promo/sync_promo_ui.cc19
-rw-r--r--chrome/browser/ui/webui/sync_promo/sync_promo_ui.h3
-rw-r--r--chrome/chrome_tests.gypi1
-rw-r--r--chrome/common/chrome_switches.cc4
-rw-r--r--chrome/common/chrome_switches.h1
-rw-r--r--google_apis/gaia/gaia_urls.cc6
-rw-r--r--google_apis/gaia/gaia_urls.h2
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_;