summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjochen <jochen@chromium.org>2015-10-26 04:19:29 -0700
committerCommit bot <commit-bot@chromium.org>2015-10-26 11:20:14 +0000
commit3917ff9e77c4da3d2d56398cebdc52312b2b63d3 (patch)
treeec6fe8230d089183e788a118665169dd27a52392
parent27af50fa8c583cce01ef87827df4fd1ac98480b5 (diff)
downloadchromium_src-3917ff9e77c4da3d2d56398cebdc52312b2b63d3.zip
chromium_src-3917ff9e77c4da3d2d56398cebdc52312b2b63d3.tar.gz
chromium_src-3917ff9e77c4da3d2d56398cebdc52312b2b63d3.tar.bz2
Implement "open link as user" context menu entry
The menu entry is only present if multiple profiles are defined, and only displays those that currently have open windows. If only a single other profile has an open window, no sub-menu is created BUG=103073 R=pkasting@chromium.org TEST=ContextMenuBrowserTest.OpenLinkInProfile* Review URL: https://codereview.chromium.org/1191453002 Cr-Commit-Position: refs/heads/master@{#356023}
-rw-r--r--chrome/app/chrome_command_ids.h5
-rw-r--r--chrome/app/generated_resources.grd12
-rw-r--r--chrome/browser/profiles/profile_info_cache.cc2
-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_metrics.h19
-rw-r--r--chrome/browser/renderer_context_menu/render_view_context_menu.cc137
-rw-r--r--chrome/browser/renderer_context_menu/render_view_context_menu.h1
-rw-r--r--chrome/browser/renderer_context_menu/render_view_context_menu_browsertest.cc112
-rw-r--r--chrome/browser/renderer_context_menu/render_view_context_menu_test_util.cc11
-rw-r--r--chrome/browser/renderer_context_menu/render_view_context_menu_test_util.h9
-rw-r--r--tools/metrics/histograms/histograms.xml4
12 files changed, 297 insertions, 20 deletions
diff --git a/chrome/app/chrome_command_ids.h b/chrome/app/chrome_command_ids.h
index 850903f..7b13dd3 100644
--- a/chrome/app/chrome_command_ids.h
+++ b/chrome/app/chrome_command_ids.h
@@ -277,6 +277,7 @@
#define IDC_CONTENT_CONTEXT_COPYEMAILADDRESS 50105
#define IDC_CONTENT_CONTEXT_OPENLINKWITH 50106
#define IDC_CONTENT_CONTEXT_COPYLINKTEXT 50107
+#define IDC_CONTENT_CONTEXT_OPENLINKINPROFILE 50108
// Image items.
#define IDC_CONTENT_CONTEXT_SAVEIMAGEAS 50110
#define IDC_CONTENT_CONTEXT_COPYIMAGELOCATION 50111
@@ -367,6 +368,10 @@
#define IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_LAST 52199
#define IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_SETTINGS 52200
+// Open link in profile entries
+#define IDC_OPEN_LINK_IN_PROFILE_FIRST 52300
+#define IDC_OPEN_LINK_IN_PROFILE_LAST 52399
+
// NOTE: The last valid command value is 57343 (0xDFFF)
// See http://msdn.microsoft.com/en-us/library/t2zechd4(VS.71).aspx
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 09316a1..d2e5c61 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -719,6 +719,12 @@ Psst! Incognito mode <ph name="SHORTCUT_KEY">$1<ex>(Ctrl+Shift+N)</ex></ph> may
<message name="IDS_CONTENT_CONTEXT_OPENLINKOFFTHERECORD" desc="The name of the open a link in incognito window command">
Open link in inco&amp;gnito window
</message>
+ <message name="IDS_CONTENT_CONTEXT_OPENLINKINPROFILES" desc="The name of the open a link as a different user context menu">
+ Open link as
+ </message>
+ <message name="IDS_CONTENT_CONTEXT_OPENLINKINPROFILE" desc="The name of the open a link as a different user command">
+ Open link as <ph name="USER">$1<ex>user@gmail.com</ex></ph>
+ </message>
<message name="IDS_CONTENT_CONTEXT_SAVELINKAS" desc="The name of the Save Link As command in the content area context menu">
Save lin&amp;k as...
@@ -929,6 +935,12 @@ Psst! Incognito mode <ph name="SHORTCUT_KEY">$1<ex>(Ctrl+Shift+N)</ex></ph> may
<message name="IDS_CONTENT_CONTEXT_OPENLINKOFFTHERECORD" desc="In Title Case: The name of the open a link in incognito window command">
Open Link in Inco&amp;gnito Window
</message>
+ <message name="IDS_CONTENT_CONTEXT_OPENLINKINPROFILES" desc="In Title Case: The name of the open a link as a different user context menu">
+ Open Link as
+ </message>
+ <message name="IDS_CONTENT_CONTEXT_OPENLINKINPROFILE" desc="In Title Case: The name of the open a link as a different user command">
+ Open Link as <ph name="USER">$1<ex>user@gmail.com</ex></ph>
+ </message>
<message name="IDS_CONTENT_CONTEXT_SAVELINKAS" desc="In Title Case: The name of the Save Link As command in the content area context menu">
Save Lin&amp;k As...
diff --git a/chrome/browser/profiles/profile_info_cache.cc b/chrome/browser/profiles/profile_info_cache.cc
index f7e8b2b..fd71e17 100644
--- a/chrome/browser/profiles/profile_info_cache.cc
+++ b/chrome/browser/profiles/profile_info_cache.cc
@@ -324,7 +324,7 @@ base::string16 ProfileInfoCache::GetUserNameOfProfileAtIndex(
}
const gfx::Image& ProfileInfoCache::GetAvatarIconOfProfileAtIndex(
- size_t index) {
+ size_t index) const {
if (IsUsingGAIAPictureOfProfileAtIndex(index)) {
const gfx::Image* image = GetGAIAPictureOfProfileAtIndex(index);
if (image)
diff --git a/chrome/browser/profiles/profile_info_cache.h b/chrome/browser/profiles/profile_info_cache.h
index 9aff678..fb99042 100644
--- a/chrome/browser/profiles/profile_info_cache.h
+++ b/chrome/browser/profiles/profile_info_cache.h
@@ -74,7 +74,7 @@ class ProfileInfoCache : public ProfileInfoInterface,
base::FilePath GetPathOfProfileAtIndex(size_t index) const override;
base::Time GetProfileActiveTimeAtIndex(size_t index) const override;
base::string16 GetUserNameOfProfileAtIndex(size_t index) const override;
- const gfx::Image& GetAvatarIconOfProfileAtIndex(size_t index) override;
+ const gfx::Image& GetAvatarIconOfProfileAtIndex(size_t index) const override;
std::string GetLocalAuthCredentialsOfProfileAtIndex(
size_t index) const override;
std::string GetPasswordChangeDetectionTokenAtIndex(
diff --git a/chrome/browser/profiles/profile_info_interface.h b/chrome/browser/profiles/profile_info_interface.h
index c1f3ec5..48a26e8 100644
--- a/chrome/browser/profiles/profile_info_interface.h
+++ b/chrome/browser/profiles/profile_info_interface.h
@@ -39,7 +39,8 @@ class ProfileInfoInterface {
virtual base::string16 GetUserNameOfProfileAtIndex(size_t index) const = 0;
- virtual const gfx::Image& GetAvatarIconOfProfileAtIndex(size_t index) = 0;
+ virtual const gfx::Image& GetAvatarIconOfProfileAtIndex(
+ size_t index) const = 0;
virtual std::string GetLocalAuthCredentialsOfProfileAtIndex(
size_t index) const = 0;
diff --git a/chrome/browser/profiles/profile_metrics.h b/chrome/browser/profiles/profile_metrics.h
index d9c4975..0b3c71f 100644
--- a/chrome/browser/profiles/profile_metrics.h
+++ b/chrome/browser/profiles/profile_metrics.h
@@ -62,15 +62,16 @@ class ProfileMetrics {
// Enum for counting the ways user profiles and menus were opened.
enum ProfileOpen {
- NTP_AVATAR_BUBBLE = 0, // User opens avatar menu from NTP
- ICON_AVATAR_BUBBLE, // User opens the avatar menu from button
- SWITCH_PROFILE_ICON, // User switches profiles from icon menu
- SWITCH_PROFILE_MENU, // User switches profiles from menu bar
- SWITCH_PROFILE_DOCK, // User switches profiles from dock (Mac-only)
- OPEN_USER_MANAGER, // User opens the User Manager
- SWITCH_PROFILE_MANAGER, // User switches profiles from the User Manager
- SWITCH_PROFILE_UNLOCK, // User switches to lockd profile via User Manager
- SWITCH_PROFILE_GUEST, // User switches to guest profile
+ NTP_AVATAR_BUBBLE = 0, // User opens avatar menu from NTP
+ ICON_AVATAR_BUBBLE, // User opens the avatar menu from button
+ SWITCH_PROFILE_ICON, // User switches profiles from icon menu
+ SWITCH_PROFILE_MENU, // User switches profiles from menu bar
+ SWITCH_PROFILE_DOCK, // User switches profiles from dock (Mac-only)
+ OPEN_USER_MANAGER, // User opens the User Manager
+ SWITCH_PROFILE_MANAGER, // User switches profiles from the User Manager
+ SWITCH_PROFILE_UNLOCK, // User switches to locked profile via User Manager
+ SWITCH_PROFILE_GUEST, // User switches to guest profile
+ SWITCH_PROFILE_CONTEXT_MENU, // User switches profiles from context menu
NUM_PROFILE_OPEN_METRICS
};
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu.cc b/chrome/browser/renderer_context_menu/render_view_context_menu.cc
index 5cc3c5e0..455ee81 100644
--- a/chrome/browser/renderer_context_menu/render_view_context_menu.cc
+++ b/chrome/browser/renderer_context_menu/render_view_context_menu.cc
@@ -37,7 +37,11 @@
#include "chrome/browser/plugins/chrome_plugin_service_filter.h"
#include "chrome/browser/prefs/incognito_mode_prefs.h"
#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_avatar_icon_util.h"
+#include "chrome/browser/profiles/profile_info_cache.h"
#include "chrome/browser/profiles/profile_io_data.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/profiles/profile_window.h"
#include "chrome/browser/renderer_context_menu/context_menu_content_type_factory.h"
#include "chrome/browser/renderer_context_menu/spelling_menu_observer.h"
#include "chrome/browser/search/search.h"
@@ -51,6 +55,7 @@
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_commands.h"
#include "chrome/browser/ui/browser_finder.h"
+#include "chrome/browser/ui/browser_navigator_params.h"
#include "chrome/browser/ui/chrome_pages.h"
#include "chrome/browser/ui/tab_contents/core_tab_helper.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
@@ -123,6 +128,10 @@
#endif // defined(ENABLE_PRINT_PREVIEW)
#endif // defined(ENABLE_PRINTING)
+#if defined(OS_CHROMEOS)
+#include "chrome/browser/chromeos/profiles/profile_helper.h"
+#endif
+
using base::UserMetricsAction;
using blink::WebContextMenuData;
using blink::WebMediaPlayerAction;
@@ -242,9 +251,11 @@ const struct UmaEnumCommandIdPair {
{67, -1, IDC_CONTENT_CONTEXT_FORCESAVEPASSWORD},
{68, -1, IDC_ROUTE_MEDIA},
{69, -1, IDC_CONTENT_CONTEXT_COPYLINKTEXT},
+ {70, -1, IDC_CONTENT_CONTEXT_OPENLINKINPROFILE},
+ {71, -1, IDC_OPEN_LINK_IN_PROFILE_FIRST},
// Add new items here and use |enum_id| from the next line.
// Also, add new items to RenderViewContextMenuItem enum in histograms.xml.
- {70, -1, 0}, // Must be the last. Increment |enum_id| when new IDC
+ {72, -1, 0}, // Must be the last. Increment |enum_id| when new IDC
// was added.
};
@@ -268,6 +279,11 @@ int CollapseCommandsForUMA(int id) {
return IDC_SPELLCHECK_SUGGESTION_0;
}
+ if (id >= IDC_OPEN_LINK_IN_PROFILE_FIRST &&
+ id <= IDC_OPEN_LINK_IN_PROFILE_LAST) {
+ return IDC_OPEN_LINK_IN_PROFILE_FIRST;
+ }
+
return id;
}
@@ -323,9 +339,8 @@ const GURL& GetDocumentURL(const content::ContextMenuParams& params) {
return params.frame_url.is_empty() ? params.page_url : params.frame_url;
}
-content::Referrer CreateSaveAsReferrer(
- const GURL& url,
- const content::ContextMenuParams& params) {
+content::Referrer CreateReferrer(const GURL& url,
+ const content::ContextMenuParams& params) {
const GURL& referring_url = GetDocumentURL(params);
return content::Referrer::SanitizeForRequest(
url,
@@ -369,6 +384,30 @@ void WriteTextToClipboard(const base::string16& text) {
bool g_custom_id_ranges_initialized = false;
+void AddIconToLastMenuItem(gfx::Image icon, ui::SimpleMenuModel* menu) {
+ int width = icon.Width();
+ int height = icon.Height();
+ gfx::CalculateFaviconTargetSize(&width, &height);
+ menu->SetIcon(menu->GetItemCount() - 1,
+ profiles::GetSizedAvatarIcon(icon, true, width, height));
+}
+
+void OnProfileCreated(chrome::HostDesktopType desktop_type,
+ const GURL& link_url,
+ const content::Referrer& referrer,
+ Profile* profile,
+ Profile::CreateStatus status) {
+ if (status == Profile::CREATE_STATUS_INITIALIZED) {
+ Browser* browser = chrome::FindLastActiveWithProfile(profile, desktop_type);
+ chrome::NavigateParams nav_params(browser, link_url,
+ ui::PAGE_TRANSITION_LINK);
+ nav_params.disposition = NEW_FOREGROUND_TAB;
+ nav_params.referrer = referrer;
+ nav_params.window_action = chrome::NavigateParams::SHOW_WINDOW;
+ chrome::Navigate(&nav_params);
+ }
+}
+
} // namespace
// static
@@ -410,6 +449,7 @@ RenderViewContextMenu::RenderViewContextMenu(
this,
&menu_model_,
base::Bind(MenuItemMatchesParams, params_)),
+ profile_link_submenu_model_(this),
protocol_handler_submenu_model_(this),
protocol_handler_registry_(
ProtocolHandlerRegistryFactory::GetForBrowserContext(GetProfile())),
@@ -812,6 +852,65 @@ void RenderViewContextMenu::AppendLinkItems() {
menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD,
IDS_CONTENT_CONTEXT_OPENLINKOFFTHERECORD);
+
+ // g_browser_process->profile_manager() is null during unit tests.
+ if (g_browser_process->profile_manager() &&
+ GetProfile()->GetProfileType() == Profile::REGULAR_PROFILE) {
+ ProfileManager* profile_manager = g_browser_process->profile_manager();
+ const ProfileInfoCache& profile_info_cache =
+ profile_manager->GetProfileInfoCache();
+
+ // Find all regular profiles other than the current one which have at
+ // least one open window.
+ std::vector<size_t> target_profiles;
+ const size_t profile_count = profile_info_cache.GetNumberOfProfiles();
+ for (size_t profile_index = 0; profile_index < profile_count;
+ ++profile_index) {
+ base::FilePath profile_path =
+ profile_info_cache.GetPathOfProfileAtIndex(profile_index);
+#if defined(OS_CHROMEOS)
+ if (profile_path == chromeos::ProfileHelper::GetSigninProfileDir())
+ continue;
+#endif
+ Profile* profile = profile_manager->GetProfileByPath(profile_path);
+ if ((profile != GetProfile()) &&
+ !profile_info_cache.IsOmittedProfileAtIndex(profile_index)) {
+ target_profiles.push_back(profile_index);
+ }
+ }
+
+ if (target_profiles.size() == 1) {
+ size_t profile_index = target_profiles[0];
+ menu_model_.AddItem(
+ IDC_OPEN_LINK_IN_PROFILE_FIRST + profile_index,
+ l10n_util::GetStringFUTF16(
+ IDS_CONTENT_CONTEXT_OPENLINKINPROFILE,
+ profile_info_cache.GetNameOfProfileAtIndex(profile_index)));
+ AddIconToLastMenuItem(
+ profile_info_cache.GetAvatarIconOfProfileAtIndex(profile_index),
+ &menu_model_);
+ } else if (target_profiles.size() > 1) {
+ for (size_t profile_index : target_profiles) {
+ // In extreme cases, we might have more profiles than available
+ // command ids. In that case, just stop creating new entries - the
+ // menu is probably useless at this point already.
+ if (IDC_OPEN_LINK_IN_PROFILE_FIRST + profile_index >
+ IDC_OPEN_LINK_IN_PROFILE_LAST)
+ break;
+ profile_link_submenu_model_.AddItem(
+ IDC_OPEN_LINK_IN_PROFILE_FIRST + profile_index,
+ profile_info_cache.GetNameOfProfileAtIndex(profile_index));
+ AddIconToLastMenuItem(
+ profile_info_cache.GetAvatarIconOfProfileAtIndex(profile_index),
+ &profile_link_submenu_model_);
+ }
+ menu_model_.AddSubMenuWithStringId(
+ IDC_CONTENT_CONTEXT_OPENLINKINPROFILE,
+ IDS_CONTENT_CONTEXT_OPENLINKINPROFILES,
+ &profile_link_submenu_model_);
+ }
+ }
+ menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVELINKAS,
IDS_CONTENT_CONTEXT_SAVELINKAS);
}
@@ -1147,6 +1246,11 @@ bool RenderViewContextMenu::IsCommandIdEnabled(int id) const {
return true;
}
+ if (id >= IDC_OPEN_LINK_IN_PROFILE_FIRST &&
+ id <= IDC_OPEN_LINK_IN_PROFILE_LAST) {
+ return params_.link_url.is_valid();
+ }
+
IncognitoModePrefs::Availability incognito_avail =
IncognitoModePrefs::GetAvailability(prefs);
switch (id) {
@@ -1223,6 +1327,7 @@ bool RenderViewContextMenu::IsCommandIdEnabled(int id) const {
case IDC_CONTENT_CONTEXT_OPENLINKNEWTAB:
case IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW:
+ case IDC_CONTENT_CONTEXT_OPENLINKINPROFILE:
return params_.link_url.is_valid();
case IDC_CONTENT_CONTEXT_COPYLINKLOCATION:
@@ -1494,6 +1599,26 @@ void RenderViewContextMenu::ExecuteCommand(int id, int event_flags) {
return;
}
+ if (id >= IDC_OPEN_LINK_IN_PROFILE_FIRST &&
+ id <= IDC_OPEN_LINK_IN_PROFILE_LAST) {
+ ProfileManager* profile_manager = g_browser_process->profile_manager();
+ const ProfileInfoCache& profile_info_cache =
+ profile_manager->GetProfileInfoCache();
+
+ base::FilePath profile_path = profile_info_cache.GetPathOfProfileAtIndex(
+ id - IDC_OPEN_LINK_IN_PROFILE_FIRST);
+ chrome::HostDesktopType desktop_type =
+ chrome::GetHostDesktopTypeForNativeView(
+ source_web_contents_->GetNativeView());
+
+ profiles::SwitchToProfile(
+ profile_path, desktop_type, false,
+ base::Bind(OnProfileCreated, desktop_type, params_.link_url,
+ CreateReferrer(params_.link_url, params_)),
+ ProfileMetrics::SWITCH_PROFILE_CONTEXT_MENU);
+ return;
+ }
+
switch (id) {
case IDC_CONTENT_CONTEXT_OPENLINKNEWTAB: {
Browser* browser =
@@ -1520,7 +1645,7 @@ void RenderViewContextMenu::ExecuteCommand(int id, int event_flags) {
case IDC_CONTENT_CONTEXT_SAVELINKAS: {
RecordDownloadSource(DOWNLOAD_INITIATED_BY_CONTEXT_MENU);
const GURL& url = params_.link_url;
- content::Referrer referrer = CreateSaveAsReferrer(url, params_);
+ content::Referrer referrer = CreateReferrer(url, params_);
DownloadManager* dlm =
BrowserContext::GetDownloadManager(browser_context_);
scoped_ptr<DownloadUrlParameters> dl_params(
@@ -1545,7 +1670,7 @@ void RenderViewContextMenu::ExecuteCommand(int id, int event_flags) {
} else {
RecordDownloadSource(DOWNLOAD_INITIATED_BY_CONTEXT_MENU);
const GURL& url = params_.src_url;
- content::Referrer referrer = CreateSaveAsReferrer(url, params_);
+ content::Referrer referrer = CreateReferrer(url, params_);
std::string headers;
DataReductionProxyChromeSettings* settings =
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu.h b/chrome/browser/renderer_context_menu/render_view_context_menu.h
index e198d4f..8312397 100644
--- a/chrome/browser/renderer_context_menu/render_view_context_menu.h
+++ b/chrome/browser/renderer_context_menu/render_view_context_menu.h
@@ -168,6 +168,7 @@ class RenderViewContextMenu : public RenderViewContextMenuBase {
// a text selection.
GURL selection_navigation_url_;
+ ui::SimpleMenuModel profile_link_submenu_model_;
ui::SimpleMenuModel protocol_handler_submenu_model_;
ProtocolHandlerRegistry* protocol_handler_registry_;
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu_browsertest.cc b/chrome/browser/renderer_context_menu/render_view_context_menu_browsertest.cc
index 18e41b1..3891232 100644
--- a/chrome/browser/renderer_context_menu/render_view_context_menu_browsertest.cc
+++ b/chrome/browser/renderer_context_menu/render_view_context_menu_browsertest.cc
@@ -10,9 +10,12 @@
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/strings/string16.h"
+#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/app/chrome_command_ids.h"
+#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/profiles/profile_window.h"
#include "chrome/browser/renderer_context_menu/render_view_context_menu.h"
#include "chrome/browser/renderer_context_menu/render_view_context_menu_browsertest_util.h"
#include "chrome/browser/renderer_context_menu/render_view_context_menu_test_util.h"
@@ -44,6 +47,11 @@
#include "third_party/WebKit/public/web/WebContextMenuData.h"
#include "third_party/WebKit/public/web/WebInputEvent.h"
+#if defined(OS_CHROMEOS)
+#include "chrome/browser/chromeos/profiles/profile_helper.h"
+#include "components/user_manager/user_manager.h"
+#endif
+
using content::WebContents;
namespace {
@@ -94,6 +102,23 @@ class ContextMenuBrowserTest : public InProcessBrowserTest {
menu->Init();
return menu;
}
+
+ Profile* CreateSecondaryProfile(int profile_num) {
+ ProfileManager* profile_manager = g_browser_process->profile_manager();
+ base::FilePath profile_path = profile_manager->user_data_dir();
+#if defined(OS_CHROMEOS)
+ std::string profile_name = base::StringPrintf("NewProfile%d", profile_num);
+ user_manager::UserManager::Get()->UserLoggedIn(
+ base::StringPrintf("user%d@test.com", profile_num), profile_name,
+ false);
+ profile_path = profile_path.Append(
+ chromeos::ProfileHelper::GetUserProfileDir(profile_name).BaseName());
+#else
+ profile_path = profile_path.AppendASCII(
+ base::StringPrintf("New Profile %d", profile_num));
+#endif
+ return profile_manager->GetProfile(profile_path);
+ }
};
IN_PROC_BROWSER_TEST_F(ContextMenuBrowserTest,
@@ -104,6 +129,9 @@ IN_PROC_BROWSER_TEST_F(ContextMenuBrowserTest,
ASSERT_TRUE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENLINKNEWTAB));
ASSERT_TRUE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW));
ASSERT_TRUE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_COPYLINKLOCATION));
+ ASSERT_FALSE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENLINKINPROFILE));
+ ASSERT_FALSE(menu->IsItemInRangePresent(IDC_OPEN_LINK_IN_PROFILE_FIRST,
+ IDC_OPEN_LINK_IN_PROFILE_LAST));
}
IN_PROC_BROWSER_TEST_F(ContextMenuBrowserTest,
@@ -114,6 +142,9 @@ IN_PROC_BROWSER_TEST_F(ContextMenuBrowserTest,
ASSERT_FALSE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENLINKNEWTAB));
ASSERT_FALSE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW));
ASSERT_TRUE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_COPYLINKLOCATION));
+ ASSERT_FALSE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENLINKINPROFILE));
+ ASSERT_FALSE(menu->IsItemInRangePresent(IDC_OPEN_LINK_IN_PROFILE_FIRST,
+ IDC_OPEN_LINK_IN_PROFILE_LAST));
}
IN_PROC_BROWSER_TEST_F(ContextMenuBrowserTest, ContextMenuForCanvas) {
@@ -397,6 +428,87 @@ IN_PROC_BROWSER_TEST_F(ContextMenuBrowserTest, OpenImageInNewTab) {
ASSERT_TRUE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB));
}
+IN_PROC_BROWSER_TEST_F(ContextMenuBrowserTest, OpenLinkInProfileEntryPresent) {
+ {
+ scoped_ptr<TestRenderViewContextMenu> menu(CreateContextMenuMediaTypeNone(
+ GURL("http://www.google.com/"), GURL("http://www.google.com/")));
+
+ ASSERT_TRUE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENLINKNEWTAB));
+ ASSERT_TRUE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW));
+ ASSERT_TRUE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_COPYLINKLOCATION));
+ // With only one profile exists, we don't add any items to the context menu
+ // for opening links in other profiles.
+ ASSERT_FALSE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENLINKINPROFILE));
+ ASSERT_FALSE(menu->IsItemInRangePresent(IDC_OPEN_LINK_IN_PROFILE_FIRST,
+ IDC_OPEN_LINK_IN_PROFILE_LAST));
+ }
+
+ // Create one additional profile, but do not yet open windows in it.
+ CreateSecondaryProfile(1);
+
+ {
+ scoped_ptr<TestRenderViewContextMenu> menu(CreateContextMenuMediaTypeNone(
+ GURL("http://www.google.com/"), GURL("http://www.google.com/")));
+
+ ASSERT_TRUE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENLINKNEWTAB));
+ ASSERT_TRUE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW));
+ ASSERT_TRUE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_COPYLINKLOCATION));
+ // With two profiles (the current and another profile), no submenu is
+ // created. Instead, a single item is added to the main context menu.
+ ASSERT_FALSE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENLINKINPROFILE));
+ ASSERT_TRUE(menu->IsItemInRangePresent(IDC_OPEN_LINK_IN_PROFILE_FIRST,
+ IDC_OPEN_LINK_IN_PROFILE_LAST));
+ }
+
+ CreateSecondaryProfile(2);
+
+ {
+ scoped_ptr<TestRenderViewContextMenu> menu(CreateContextMenuMediaTypeNone(
+ GURL("http://www.google.com/"), GURL("http://www.google.com/")));
+
+ ASSERT_TRUE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENLINKNEWTAB));
+ ASSERT_TRUE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW));
+ ASSERT_TRUE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_COPYLINKLOCATION));
+ // As soon as at least three profiles exist, we show all profiles in a
+ // submenu.
+ ASSERT_TRUE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENLINKINPROFILE));
+ ASSERT_FALSE(menu->IsItemInRangePresent(IDC_OPEN_LINK_IN_PROFILE_FIRST,
+ IDC_OPEN_LINK_IN_PROFILE_LAST));
+ }
+}
+
+IN_PROC_BROWSER_TEST_F(ContextMenuBrowserTest, OpenLinkInProfile) {
+ Profile* other_profile = CreateSecondaryProfile(1);
+ profiles::FindOrCreateNewWindowForProfile(
+ other_profile, chrome::startup::IS_NOT_PROCESS_STARTUP,
+ chrome::startup::IS_NOT_FIRST_RUN, chrome::GetActiveDesktop(), false);
+
+ ui_test_utils::WindowedTabAddedNotificationObserver tab_observer(
+ content::NotificationService::AllSources());
+
+ ASSERT_TRUE(test_server()->Start());
+ GURL url(test_server()->GetURL(std::string()));
+
+ scoped_ptr<TestRenderViewContextMenu> menu(
+ CreateContextMenuMediaTypeNone(url, url));
+
+ menu->ExecuteCommand(
+ IDC_OPEN_LINK_IN_PROFILE_FIRST +
+ g_browser_process->profile_manager()
+ ->GetProfileInfoCache()
+ .GetIndexOfProfileWithPath(other_profile->GetPath()),
+ 0);
+
+ tab_observer.Wait();
+ content::WebContents* tab = tab_observer.GetTab();
+ content::WaitForLoadStop(tab);
+
+ // Verify that it's the correct tab and profile.
+ ASSERT_EQ(url, tab->GetURL());
+ ASSERT_EQ(other_profile,
+ Profile::FromBrowserContext(tab->GetBrowserContext()));
+}
+
class ThumbnailResponseWatcher : public content::NotificationObserver {
public:
enum QuitReason {
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu_test_util.cc b/chrome/browser/renderer_context_menu/render_view_context_menu_test_util.cc
index 0465a71..e197c23 100644
--- a/chrome/browser/renderer_context_menu/render_view_context_menu_test_util.cc
+++ b/chrome/browser/renderer_context_menu/render_view_context_menu_test_util.cc
@@ -42,6 +42,17 @@ bool TestRenderViewContextMenu::IsItemPresent(int command_id) {
return menu_model_.GetIndexOfCommandId(command_id) != -1;
}
+bool TestRenderViewContextMenu::IsItemInRangePresent(int command_id_first,
+ int command_id_last) {
+ DCHECK_LE(command_id_first, command_id_last);
+ for (int command_id = command_id_first; command_id <= command_id_last;
+ ++command_id) {
+ if (IsItemPresent(command_id))
+ return true;
+ }
+ return false;
+}
+
bool TestRenderViewContextMenu::GetMenuModelAndItemIndex(
int command_id,
MenuModel** found_model,
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu_test_util.h b/chrome/browser/renderer_context_menu/render_view_context_menu_test_util.h
index 52cb904..c0fc272 100644
--- a/chrome/browser/renderer_context_menu/render_view_context_menu_test_util.h
+++ b/chrome/browser/renderer_context_menu/render_view_context_menu_test_util.h
@@ -41,11 +41,16 @@ class TestRenderViewContextMenu : public RenderViewContextMenu {
bool GetAcceleratorForCommandId(int command_id,
ui::Accelerator* accelerator) override;
- // Returns true if command specified by |command_id| is present
+ // Returns true if the command specified by |command_id| is present
// in the menu.
- // List of command ids can be found in chrome/app/chrome_command_ids.h.
+ // A list of command ids can be found in chrome/app/chrome_command_ids.h.
bool IsItemPresent(int command_id);
+ // Returns true if a command specified by any command id between
+ // |command_id_first| and |command_id_last| (inclusive) is present in the
+ // menu.
+ bool IsItemInRangePresent(int command_id_first, int command_id_last);
+
// Searches for an menu item with |command_id|. If it's found, the return
// value is true and the model and index where it appears in that model are
// returned in |found_model| and |found_index|. Otherwise returns false.
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 4ad8984..f792d40 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -69907,6 +69907,7 @@ To add a new entry, add it with any value and run test to compute valid value.
<int value="6" label="Switch to profile via User Manager"/>
<int value="7" label="Switch to locked profile via User Manager"/>
<int value="8" label="Switch to Guest profile"/>
+ <int value="9" label="Switch to profile from context menu"/>
</enum>
<enum name="ProfileSigninStatus" type="int">
@@ -70747,7 +70748,10 @@ To add a new entry, add it with any value and run test to compute valid value.
<int value="65" label="IDC_WRITING_DIRECTION_RTL"/>
<int value="66" label="IDC_CONTENT_CONTEXT_LOAD_ORIGINAL_IMAGE"/>
<int value="67" label="IDC_CONTENT_CONTEXT_FORCESAVEPASSWORD"/>
+ <int value="68" label="IDC_ROUTE_MEDIA"/>
<int value="69" label="IDC_CONTENT_CONTEXT_COPYLINKTEXT"/>
+ <int value="70" label="IDC_CONTENT_CONTEXT_OPENLINKINPROFILE"/>
+ <int value="71" label="IDC_OPEN_LINK_IN_PROFILE_FIRST"/>
</enum>
<enum name="ReportProcessingResult" type="int">