diff options
author | finnur@chromium.org <finnur@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-06-07 00:44:23 +0000 |
---|---|---|
committer | finnur@chromium.org <finnur@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-06-07 00:44:23 +0000 |
commit | 8dc56d0f6ed6e59c93b20ef0d4cec99e411ed050 (patch) | |
tree | eda45fac6d66144d799e583b438dd78c0e3ef6e4 | |
parent | 8f4bba4f2f7a0d75ebd66955b53af2876ef267e5 (diff) | |
download | chromium_src-8dc56d0f6ed6e59c93b20ef0d4cec99e411ed050.zip chromium_src-8dc56d0f6ed6e59c93b20ef0d4cec99e411ed050.tar.gz chromium_src-8dc56d0f6ed6e59c93b20ef0d4cec99e411ed050.tar.bz2 |
Add an extension override bubble and warning box for proxy extensions. (2nd attempt, this time with two one-liner test fixes)
Also use the browser action highlighting for extensions that have a browser action icon.
NOTE: This CL was already green-lighted here:
https://codereview.chromium.org/288923004/
BUG=381291
TBR=sky, devlin, dbeam
Review URL: https://codereview.chromium.org/320633002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@275577 0039d316-1c4b-4281-b951-d872f2087c98
23 files changed, 866 insertions, 219 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index b91ddb9..a71d72c 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd @@ -5170,8 +5170,18 @@ Keep your key file in a safe place. You will need it to create new versions of y Is this the new tab page you were expecting? </message> </if> + <if expr="use_titlecase"> + <message name="IDS_EXTENSIONS_PROXY_CONTROLLED_TITLE_HOME_PAGE_BUBBLE" desc="In Title Case: Title of a bubble warning users that an extension has overridden their proxy setting"> + Your Internet Connection is Being Controlled + </message> + </if> + <if expr="not use_titlecase"> + <message name="IDS_EXTENSIONS_PROXY_CONTROLLED_TITLE_HOME_PAGE_BUBBLE" desc="Title of a bubble warning users that an extension has overridden their proxy setting"> + Your Internet connection is being controlled + </message> + </if> - <message name="IDS_EXTENSIONS_SETTINGS_API_FIRST_LINE_SEARCH_ENGINE" desc="Text displayed in the Settings API bubble as first line when an extension has changed the search engine."> + <message name="IDS_EXTENSIONS_SETTINGS_API_FIRST_LINE_SEARCH_ENGINE" desc="Text displayed as the first line in the Settings API bubble when an extension has changed the search engine."> An extension has changed what page is shown when you search from the Omnibox. </message> <message name="IDS_EXTENSIONS_SETTINGS_API_FIRST_LINE_HOME_PAGE" desc="Text displayed in the Settings API bubble as first line when an extension has changed the home page."> @@ -5188,10 +5198,17 @@ Keep your key file in a safe place. You will need it to create new versions of y ''' It also controls what page is shown when you click the Home button or search from the Omnibox. ''' </message> - <message name="IDS_EXTENSIONS_NTP_CONTROLLED_FIRST_LINE" desc="Text displayed in the Settings API bubble as first line when an extension has changed the new tab page."> + <message name="IDS_EXTENSIONS_NTP_CONTROLLED_FIRST_LINE" desc="Text displayed as the first line in the NTP bubble when an extension has changed the new tab page."> An extension has changed what page is shown when you open a new tab. </message> + <message name="IDS_EXTENSIONS_PROXY_CONTROLLED_FIRST_LINE" desc="Text displayed as the first line in the proxy bubble when an extension has changed the proxy but we are not pointing at it's icon (because it doesn't have one)."> + An extension has taken control of your proxy settings, which means it can change, break, or eavesdrop on anything you do online. If you aren't sure why this change happened, you probably don't want it. + </message> + <message name="IDS_EXTENSIONS_PROXY_CONTROLLED_FIRST_LINE_EXTENSION_SPECIFIC" desc="Text displayed as the first line in the proxy bubble when an extension has changed the proxy and we are pointing at that extension's icon."> + This extension has taken control of your proxy settings, which means it can change, break, or eavesdrop on anything you do online. If you aren't sure why this change happened, you probably don't want it. + </message> + <message name="IDS_EXTENSIONS_SETTINGS_API_THIRD_LINE_CONFIRMATION" desc="Third line in the Settings API bubble, always appended after the first (and optional second) line to make one paragraph. See IDS_EXTENSIONS_SETTINGS_API_SECOND_LINE_SEARCH_ENGINE for reason for triple quotes."> ''' If you didn't want these changes, you can restore your previous settings.''' </message> @@ -9644,6 +9661,9 @@ Chrome ran out of memory. <message name="IDS_OPTIONS_STARTUP_USE_CURRENT" desc="The label of the 'Use Current' button for the custom startup urls list"> Use current pages </message> + <message name="IDS_OPTIONS_PROXY_GROUP_NAME" desc="The title of the Proxy group"> + Proxy + </message> <message name="IDS_OPTIONS_DEFAULTSEARCH_MANAGE_ENGINES" desc="The label of the 'Manage search engines' button"> Manage search engines... </message> diff --git a/chrome/browser/extensions/dev_mode_bubble_controller.cc b/chrome/browser/extensions/dev_mode_bubble_controller.cc index 8026fc8..f2c2400 100644 --- a/chrome/browser/extensions/dev_mode_bubble_controller.cc +++ b/chrome/browser/extensions/dev_mode_bubble_controller.cc @@ -45,7 +45,8 @@ class DevModeBubbleDelegate virtual void PerformAction(const ExtensionIdList& list) OVERRIDE; virtual void OnClose() OVERRIDE; virtual base::string16 GetTitle() const OVERRIDE; - virtual base::string16 GetMessageBody() const OVERRIDE; + virtual base::string16 GetMessageBody( + bool anchored_to_browser_action) const OVERRIDE; virtual base::string16 GetOverflowText( const base::string16& overflow_count) const OVERRIDE; virtual base::string16 GetLearnMoreLabel() const OVERRIDE; @@ -102,7 +103,8 @@ base::string16 DevModeBubbleDelegate::GetTitle() const { return l10n_util::GetStringUTF16(IDS_EXTENSIONS_DISABLE_DEVELOPER_MODE_TITLE); } -base::string16 DevModeBubbleDelegate::GetMessageBody() const { +base::string16 DevModeBubbleDelegate::GetMessageBody( + bool anchored_to_browser_action) const { return l10n_util::GetStringUTF16(IDS_EXTENSIONS_DISABLE_DEVELOPER_MODE_BODY); } diff --git a/chrome/browser/extensions/extension_message_bubble_controller.h b/chrome/browser/extensions/extension_message_bubble_controller.h index e2a64fd..e3f522d 100644 --- a/chrome/browser/extensions/extension_message_bubble_controller.h +++ b/chrome/browser/extensions/extension_message_bubble_controller.h @@ -42,7 +42,13 @@ class ExtensionMessageBubbleController { // Text for various UI labels shown in the bubble. virtual base::string16 GetTitle() const = 0; - virtual base::string16 GetMessageBody() const = 0; + // Fetches the message to show in the body. |anchored_to_browser_action| + // will be true if the bubble is anchored against a specific extension + // icon, allowing the bubble to show a different message than when it is + // anchored against something else (e.g. show "This extension has..." + // instead of "An extension has..."). + virtual base::string16 GetMessageBody( + bool anchored_to_browser_action) const = 0; virtual base::string16 GetOverflowText( const base::string16& overflow_count) const = 0; virtual base::string16 GetLearnMoreLabel() const = 0; diff --git a/chrome/browser/extensions/extension_message_bubble_controller_unittest.cc b/chrome/browser/extensions/extension_message_bubble_controller_unittest.cc index 6eed045..b33c31b 100644 --- a/chrome/browser/extensions/extension_message_bubble_controller_unittest.cc +++ b/chrome/browser/extensions/extension_message_bubble_controller_unittest.cc @@ -3,23 +3,31 @@ // found in the LICENSE file. #include "base/command_line.h" +#include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" +#include "base/values.h" #include "chrome/browser/extensions/dev_mode_bubble_controller.h" #include "chrome/browser/extensions/extension_function_test_utils.h" #include "chrome/browser/extensions/extension_message_bubble.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/ntp_overridden_bubble_controller.h" +#include "chrome/browser/extensions/proxy_overridden_bubble_controller.h" #include "chrome/browser/extensions/settings_api_bubble_controller.h" #include "chrome/browser/extensions/suspicious_extension_bubble_controller.h" #include "chrome/browser/extensions/test_extension_system.h" #include "chrome/common/chrome_version_info.h" +#include "chrome/common/pref_names.h" #include "chrome/test/base/testing_profile.h" #include "content/public/test/test_browser_thread_bundle.h" +#include "extensions/browser/extension_pref_value_map.h" +#include "extensions/browser/extension_pref_value_map_factory.h" #include "extensions/browser/extension_prefs.h" +#include "extensions/browser/extension_registry.h" #include "extensions/common/extension.h" #include "extensions/common/extension_builder.h" #include "extensions/common/feature_switch.h" +#include "extensions/common/value_builder.h" namespace { @@ -159,6 +167,31 @@ class TestNtpOverriddenBubbleController } }; +// A test class for the ProxyOverriddenBubbleController. +class TestProxyOverriddenBubbleController + : public ProxyOverriddenBubbleController, + public TestDelegate { + public: + explicit TestProxyOverriddenBubbleController(Profile* profile) + : ProxyOverriddenBubbleController(profile) { + } + + virtual void OnBubbleAction() OVERRIDE { + ++action_button_callback_count_; + ProxyOverriddenBubbleController::OnBubbleAction(); + } + + virtual void OnBubbleDismiss() OVERRIDE { + ++dismiss_button_callback_count_; + ProxyOverriddenBubbleController::OnBubbleDismiss(); + } + + virtual void OnLinkClicked() OVERRIDE { + ++link_click_callback_count_; + ProxyOverriddenBubbleController::OnLinkClicked(); + } +}; + // A fake bubble used for testing the controller. Takes an action that specifies // what should happen when the bubble is "shown" (the bubble is actually not // shown, the corresponding action is taken immediately). @@ -209,84 +242,146 @@ class ExtensionMessageBubbleTest : public testing::Test { public: ExtensionMessageBubbleTest() {} - void LoadGenericExtension(const std::string& index, - const std::string& id, - Manifest::Location location) { - extensions::ExtensionBuilder builder; - builder.SetManifest(extensions::DictionaryBuilder() + testing::AssertionResult LoadGenericExtension(const std::string& index, + const std::string& id, + Manifest::Location location) { + ExtensionBuilder builder; + builder.SetManifest(DictionaryBuilder() .Set("name", std::string("Extension " + index)) .Set("version", "1.0") .Set("manifest_version", 2)); builder.SetLocation(location); builder.SetID(id); service_->AddExtension(builder.Build().get()); + + if (ExtensionRegistry::Get(profile())->enabled_extensions().GetByID(id)) + return testing::AssertionSuccess(); + return testing::AssertionFailure() << "Could not install extension: " << id; } - void LoadExtensionWithAction(const std::string& index, - const std::string& id, - Manifest::Location location) { - extensions::ExtensionBuilder builder; - builder.SetManifest(extensions::DictionaryBuilder() + testing::AssertionResult LoadExtensionWithAction( + const std::string& index, + const std::string& id, + Manifest::Location location) { + ExtensionBuilder builder; + builder.SetManifest(DictionaryBuilder() .Set("name", std::string("Extension " + index)) .Set("version", "1.0") .Set("manifest_version", 2) .Set("browser_action", - extensions::DictionaryBuilder().Set( + DictionaryBuilder().Set( "default_title", "Default title"))); builder.SetLocation(location); builder.SetID(id); service_->AddExtension(builder.Build().get()); + + if (ExtensionRegistry::Get(profile())->enabled_extensions().GetByID(id)) + return testing::AssertionSuccess(); + return testing::AssertionFailure() << "Could not install extension: " << id; } - void LoadExtensionOverridingHome(const std::string& index, - const std::string& id, - Manifest::Location location) { - extensions::ExtensionBuilder builder; - builder.SetManifest(extensions::DictionaryBuilder() + testing::AssertionResult LoadExtensionOverridingHome( + const std::string& index, + const std::string& id, + Manifest::Location location) { + ExtensionBuilder builder; + builder.SetManifest(DictionaryBuilder() .Set("name", std::string("Extension " + index)) .Set("version", "1.0") .Set("manifest_version", 2) .Set("chrome_settings_overrides", - extensions::DictionaryBuilder().Set( + DictionaryBuilder().Set( "homepage", "http://www.google.com"))); builder.SetLocation(location); builder.SetID(id); service_->AddExtension(builder.Build().get()); + + if (ExtensionRegistry::Get(profile())->enabled_extensions().GetByID(id)) + return testing::AssertionSuccess(); + return testing::AssertionFailure() << "Could not install extension: " << id; } - void LoadExtensionOverridingStart(const std::string& index, - const std::string& id, - Manifest::Location location) { - extensions::ExtensionBuilder builder; - builder.SetManifest(extensions::DictionaryBuilder() + testing::AssertionResult LoadExtensionOverridingStart( + const std::string& index, + const std::string& id, + Manifest::Location location) { + ExtensionBuilder builder; + builder.SetManifest(DictionaryBuilder() .Set("name", std::string("Extension " + index)) .Set("version", "1.0") .Set("manifest_version", 2) .Set("chrome_settings_overrides", - extensions::DictionaryBuilder().Set( + DictionaryBuilder().Set( "startup_pages", - extensions::ListBuilder().Append( + ListBuilder().Append( "http://www.google.com")))); builder.SetLocation(location); builder.SetID(id); service_->AddExtension(builder.Build().get()); + + if (ExtensionRegistry::Get(profile())->enabled_extensions().GetByID(id)) + return testing::AssertionSuccess(); + return testing::AssertionFailure() << "Could not install extension: " << id; } - void LoadExtensionOverridingNtp(const std::string& index, - const std::string& id, - Manifest::Location location) { - extensions::ExtensionBuilder builder; - builder.SetManifest(extensions::DictionaryBuilder() + testing::AssertionResult LoadExtensionOverridingNtp( + const std::string& index, + const std::string& id, + Manifest::Location location) { + ExtensionBuilder builder; + builder.SetManifest(DictionaryBuilder() .Set("name", std::string("Extension " + index)) .Set("version", "1.0") .Set("manifest_version", 2) .Set("chrome_url_overrides", - extensions::DictionaryBuilder().Set( + DictionaryBuilder().Set( "newtab", "Default.html"))); builder.SetLocation(location); builder.SetID(id); service_->AddExtension(builder.Build().get()); + + if (ExtensionRegistry::Get(profile())->enabled_extensions().GetByID(id)) + return testing::AssertionSuccess(); + return testing::AssertionFailure() << "Could not install extension: " << id; + } + + testing::AssertionResult LoadExtensionOverridingProxy( + const std::string& index, + const std::string& id, + Manifest::Location location) { + ExtensionBuilder builder; + builder.SetManifest(DictionaryBuilder() + .Set("name", std::string("Extension " + index)) + .Set("version", "1.0") + .Set("manifest_version", 2) + .Set("permissions", + ListBuilder().Append("proxy"))); + + builder.SetLocation(location); + builder.SetID(id); + service_->AddExtension(builder.Build().get()); + + // The proxy check relies on ExtensionPrefValueMap being up to date as to + // specifying which extension is controlling the proxy, but unfortunately + // that Map is not updated automatically for unit tests, so we simulate the + // update here to avoid test failures. + ExtensionPrefValueMap* extension_prefs_value_map = + ExtensionPrefValueMapFactory::GetForBrowserContext(profile()); + extension_prefs_value_map->RegisterExtension( + id, + base::Time::Now(), + true, // is_enabled. + false); // is_incognito_enabled. + extension_prefs_value_map->SetExtensionPref( + id, + prefs::kProxy, + kExtensionPrefsScopeRegular, + base::Value::CreateStringValue(id)); + + if (ExtensionRegistry::Get(profile())->enabled_extensions().GetByID(id)) + return testing::AssertionSuccess(); + return testing::AssertionFailure() << "Could not install extension: " << id; } void Init() { @@ -348,9 +443,9 @@ TEST_F(ExtensionMessageBubbleTest, MAYBE_WipeoutControllerTest) { Init(); // Add three extensions, and control two of them in this test (extension 1 // and 2). - LoadExtensionWithAction("1", kId1, Manifest::COMMAND_LINE); - LoadGenericExtension("2", kId2, Manifest::UNPACKED); - LoadGenericExtension("3", kId3, Manifest::EXTERNAL_POLICY); + ASSERT_TRUE(LoadExtensionWithAction("1", kId1, Manifest::COMMAND_LINE)); + ASSERT_TRUE(LoadGenericExtension("2", kId2, Manifest::UNPACKED)); + ASSERT_TRUE(LoadGenericExtension("3", kId3, Manifest::EXTERNAL_POLICY)); scoped_ptr<TestSuspiciousExtensionBubbleController> controller( new TestSuspiciousExtensionBubbleController(profile())); @@ -425,9 +520,9 @@ TEST_F(ExtensionMessageBubbleTest, MAYBE_DevModeControllerTest) { // Add three extensions, and control two of them in this test (extension 1 // and 2). Extension 1 is a regular extension, Extension 2 is UNPACKED so it // counts as a DevMode extension. - LoadExtensionWithAction("1", kId1, Manifest::COMMAND_LINE); - LoadGenericExtension("2", kId2, Manifest::UNPACKED); - LoadGenericExtension("3", kId3, Manifest::EXTERNAL_POLICY); + ASSERT_TRUE(LoadExtensionWithAction("1", kId1, Manifest::COMMAND_LINE)); + ASSERT_TRUE(LoadGenericExtension("2", kId2, Manifest::UNPACKED)); + ASSERT_TRUE(LoadGenericExtension("3", kId3, Manifest::EXTERNAL_POLICY)); scoped_ptr<TestDevModeBubbleController> controller( new TestDevModeBubbleController(profile())); @@ -451,8 +546,9 @@ TEST_F(ExtensionMessageBubbleTest, MAYBE_DevModeControllerTest) { EXPECT_EQ(0U, controller->link_click_count()); EXPECT_EQ(0U, controller->action_click_count()); EXPECT_EQ(1U, controller->dismiss_click_count()); - EXPECT_TRUE(service_->GetExtensionById(kId1, false) != NULL); - EXPECT_TRUE(service_->GetExtensionById(kId2, false) != NULL); + ExtensionRegistry* registry = ExtensionRegistry::Get(profile()); + EXPECT_TRUE(registry->enabled_extensions().GetByID(kId1) != NULL); + EXPECT_TRUE(registry->enabled_extensions().GetByID(kId2) != NULL); // Do it again, but now press different button (Disable). bubble.set_action_on_show( @@ -467,8 +563,8 @@ TEST_F(ExtensionMessageBubbleTest, MAYBE_DevModeControllerTest) { EXPECT_EQ(0U, controller->link_click_count()); EXPECT_EQ(1U, controller->action_click_count()); EXPECT_EQ(0U, controller->dismiss_click_count()); - EXPECT_TRUE(service_->GetExtensionById(kId1, false) == NULL); - EXPECT_TRUE(service_->GetExtensionById(kId2, false) == NULL); + EXPECT_TRUE(registry->disabled_extensions().GetByID(kId1) != NULL); + EXPECT_TRUE(registry->disabled_extensions().GetByID(kId2) != NULL); // Re-enable the extensions (disabled by the action button above). service_->EnableExtension(kId1); @@ -487,8 +583,8 @@ TEST_F(ExtensionMessageBubbleTest, MAYBE_DevModeControllerTest) { EXPECT_EQ(1U, controller->link_click_count()); EXPECT_EQ(0U, controller->action_click_count()); EXPECT_EQ(0U, controller->dismiss_click_count()); - EXPECT_TRUE(service_->GetExtensionById(kId1, false) != NULL); - EXPECT_TRUE(service_->GetExtensionById(kId2, false) != NULL); + EXPECT_TRUE(registry->enabled_extensions().GetByID(kId1) != NULL); + EXPECT_TRUE(registry->enabled_extensions().GetByID(kId2) != NULL); // Now disable the unpacked extension. service_->DisableExtension(kId1, Extension::DISABLE_USER_ACTION); @@ -511,8 +607,7 @@ TEST_F(ExtensionMessageBubbleTest, MAYBE_DevModeControllerTest) { TEST_F(ExtensionMessageBubbleTest, MAYBE_SettingsApiControllerTest) { Init(); - extensions::ExtensionPrefs* prefs = - extensions::ExtensionPrefs::Get(profile()); + ExtensionPrefs* prefs = ExtensionPrefs::Get(profile()); for (int i = 0; i < 3; ++i) { switch (static_cast<SettingsApiOverrideType>(i)) { @@ -520,9 +615,10 @@ TEST_F(ExtensionMessageBubbleTest, MAYBE_SettingsApiControllerTest) { // Load two extensions overriding home page and one overriding something // unrelated (to check for interference). Extension 2 should still win // on the home page setting. - LoadExtensionOverridingHome("1", kId1, Manifest::UNPACKED); - LoadExtensionOverridingHome("2", kId2, Manifest::UNPACKED); - LoadExtensionOverridingStart("3", kId3, Manifest::UNPACKED); + ASSERT_TRUE(LoadExtensionOverridingHome("1", kId1, Manifest::UNPACKED)); + ASSERT_TRUE(LoadExtensionOverridingHome("2", kId2, Manifest::UNPACKED)); + ASSERT_TRUE( + LoadExtensionOverridingStart("3", kId3, Manifest::UNPACKED)); break; case BUBBLE_TYPE_SEARCH_ENGINE: // We deliberately skip testing the search engine since it relies on @@ -535,9 +631,11 @@ TEST_F(ExtensionMessageBubbleTest, MAYBE_SettingsApiControllerTest) { // Load two extensions overriding start page and one overriding // something unrelated (to check for interference). Extension 2 should // still win on the startup page setting. - LoadExtensionOverridingStart("1", kId1, Manifest::UNPACKED); - LoadExtensionOverridingStart("2", kId2, Manifest::UNPACKED); - LoadExtensionOverridingHome("3", kId3, Manifest::UNPACKED); + ASSERT_TRUE( + LoadExtensionOverridingStart("1", kId1, Manifest::UNPACKED)); + ASSERT_TRUE( + LoadExtensionOverridingStart("2", kId2, Manifest::UNPACKED)); + ASSERT_TRUE(LoadExtensionOverridingHome("3", kId3, Manifest::UNPACKED)); break; default: NOTREACHED(); @@ -568,9 +666,10 @@ TEST_F(ExtensionMessageBubbleTest, MAYBE_SettingsApiControllerTest) { EXPECT_EQ(0U, controller->action_click_count()); EXPECT_EQ(1U, controller->dismiss_click_count()); // No extension should have become disabled. - EXPECT_TRUE(service_->GetExtensionById(kId1, false) != NULL); - EXPECT_TRUE(service_->GetExtensionById(kId2, false) != NULL); - EXPECT_TRUE(service_->GetExtensionById(kId3, false) != NULL); + ExtensionRegistry* registry = ExtensionRegistry::Get(profile()); + EXPECT_TRUE(registry->enabled_extensions().GetByID(kId1) != NULL); + EXPECT_TRUE(registry->enabled_extensions().GetByID(kId2) != NULL); + EXPECT_TRUE(registry->enabled_extensions().GetByID(kId3) != NULL); // Only extension 2 should have been acknowledged. EXPECT_FALSE(prefs->HasSettingsApiBubbleBeenAcknowledged(kId1)); EXPECT_TRUE(prefs->HasSettingsApiBubbleBeenAcknowledged(kId2)); @@ -588,9 +687,9 @@ TEST_F(ExtensionMessageBubbleTest, MAYBE_SettingsApiControllerTest) { EXPECT_EQ(0U, controller->action_click_count()); EXPECT_EQ(0U, controller->dismiss_click_count()); // No extension should have become disabled. - EXPECT_TRUE(service_->GetExtensionById(kId1, false) != NULL); - EXPECT_TRUE(service_->GetExtensionById(kId2, false) != NULL); - EXPECT_TRUE(service_->GetExtensionById(kId3, false) != NULL); + EXPECT_TRUE(registry->enabled_extensions().GetByID(kId1) != NULL); + EXPECT_TRUE(registry->enabled_extensions().GetByID(kId2) != NULL); + EXPECT_TRUE(registry->enabled_extensions().GetByID(kId3) != NULL); // Only extension 2 should have been acknowledged. EXPECT_FALSE(prefs->HasSettingsApiBubbleBeenAcknowledged(kId1)); EXPECT_TRUE(prefs->HasSettingsApiBubbleBeenAcknowledged(kId2)); @@ -611,9 +710,9 @@ TEST_F(ExtensionMessageBubbleTest, MAYBE_SettingsApiControllerTest) { EXPECT_EQ(1U, controller->action_click_count()); EXPECT_EQ(0U, controller->dismiss_click_count()); // Only extension 2 should have become disabled. - EXPECT_TRUE(service_->GetExtensionById(kId1, false) != NULL); - EXPECT_TRUE(service_->GetExtensionById(kId2, false) == NULL); - EXPECT_TRUE(service_->GetExtensionById(kId3, false) != NULL); + EXPECT_TRUE(registry->enabled_extensions().GetByID(kId1) != NULL); + EXPECT_TRUE(registry->disabled_extensions().GetByID(kId2) != NULL); + EXPECT_TRUE(registry->enabled_extensions().GetByID(kId3) != NULL); // No extension should have been acknowledged (it got disabled). EXPECT_FALSE(prefs->HasSettingsApiBubbleBeenAcknowledged(kId1)); EXPECT_FALSE(prefs->HasSettingsApiBubbleBeenAcknowledged(kId2)); @@ -635,14 +734,13 @@ TEST_F(ExtensionMessageBubbleTest, MAYBE_SettingsApiControllerTest) { TEST_F(ExtensionMessageBubbleTest, MAYBE_NtpOverriddenControllerTest) { Init(); - extensions::ExtensionPrefs* prefs = - extensions::ExtensionPrefs::Get(profile()); + ExtensionPrefs* prefs = ExtensionPrefs::Get(profile()); // Load two extensions overriding new tab page and one overriding something // unrelated (to check for interference). Extension 2 should still win // on the new tab page setting. - LoadExtensionOverridingNtp("1", kId1, Manifest::UNPACKED); - LoadExtensionOverridingNtp("2", kId2, Manifest::UNPACKED); - LoadExtensionOverridingStart("3", kId3, Manifest::UNPACKED); + ASSERT_TRUE(LoadExtensionOverridingNtp("1", kId1, Manifest::UNPACKED)); + ASSERT_TRUE(LoadExtensionOverridingNtp("2", kId2, Manifest::UNPACKED)); + ASSERT_TRUE(LoadExtensionOverridingStart("3", kId3, Manifest::UNPACKED)); scoped_ptr<TestNtpOverriddenBubbleController> controller( new TestNtpOverriddenBubbleController(profile())); @@ -668,9 +766,10 @@ TEST_F(ExtensionMessageBubbleTest, MAYBE_NtpOverriddenControllerTest) { EXPECT_EQ(0U, controller->action_click_count()); EXPECT_EQ(1U, controller->dismiss_click_count()); // No extension should have become disabled. - EXPECT_TRUE(service_->GetExtensionById(kId1, false) != NULL); - EXPECT_TRUE(service_->GetExtensionById(kId2, false) != NULL); - EXPECT_TRUE(service_->GetExtensionById(kId3, false) != NULL); + ExtensionRegistry* registry = ExtensionRegistry::Get(profile()); + EXPECT_TRUE(registry->enabled_extensions().GetByID(kId1) != NULL); + EXPECT_TRUE(registry->enabled_extensions().GetByID(kId2) != NULL); + EXPECT_TRUE(registry->enabled_extensions().GetByID(kId3) != NULL); // Only extension 2 should have been acknowledged. EXPECT_FALSE(prefs->HasNtpOverriddenBubbleBeenAcknowledged(kId1)); EXPECT_TRUE(prefs->HasNtpOverriddenBubbleBeenAcknowledged(kId2)); @@ -688,9 +787,9 @@ TEST_F(ExtensionMessageBubbleTest, MAYBE_NtpOverriddenControllerTest) { EXPECT_EQ(0U, controller->action_click_count()); EXPECT_EQ(0U, controller->dismiss_click_count()); // No extension should have become disabled. - EXPECT_TRUE(service_->GetExtensionById(kId1, false) != NULL); - EXPECT_TRUE(service_->GetExtensionById(kId2, false) != NULL); - EXPECT_TRUE(service_->GetExtensionById(kId3, false) != NULL); + EXPECT_TRUE(registry->enabled_extensions().GetByID(kId1) != NULL); + EXPECT_TRUE(registry->enabled_extensions().GetByID(kId2) != NULL); + EXPECT_TRUE(registry->enabled_extensions().GetByID(kId3) != NULL); // Only extension 2 should have been acknowledged. EXPECT_FALSE(prefs->HasNtpOverriddenBubbleBeenAcknowledged(kId1)); EXPECT_TRUE(prefs->HasNtpOverriddenBubbleBeenAcknowledged(kId2)); @@ -710,9 +809,9 @@ TEST_F(ExtensionMessageBubbleTest, MAYBE_NtpOverriddenControllerTest) { EXPECT_EQ(1U, controller->action_click_count()); EXPECT_EQ(0U, controller->dismiss_click_count()); // Only extension 2 should have become disabled. - EXPECT_TRUE(service_->GetExtensionById(kId1, false) != NULL); - EXPECT_TRUE(service_->GetExtensionById(kId2, false) == NULL); - EXPECT_TRUE(service_->GetExtensionById(kId3, false) != NULL); + EXPECT_TRUE(registry->enabled_extensions().GetByID(kId1) != NULL); + EXPECT_TRUE(registry->disabled_extensions().GetByID(kId2) != NULL); + EXPECT_TRUE(registry->enabled_extensions().GetByID(kId3) != NULL); // No extension should have been acknowledged (it got disabled). EXPECT_FALSE(prefs->HasNtpOverriddenBubbleBeenAcknowledged(kId1)); EXPECT_FALSE(prefs->HasNtpOverriddenBubbleBeenAcknowledged(kId2)); @@ -724,4 +823,124 @@ TEST_F(ExtensionMessageBubbleTest, MAYBE_NtpOverriddenControllerTest) { service_->UninstallExtension(kId3, false, NULL); } +void SetInstallTime(const std::string& extension_id, + const base::Time& time, + ExtensionPrefs* prefs) { + std::string time_str = base::Int64ToString(time.ToInternalValue()); + prefs->UpdateExtensionPref(extension_id, + "install_time", + new base::StringValue(time_str)); +} + +// The feature this is meant to test is only implemented on Windows. +#if defined(OS_WIN) +#define MAYBE_ProxyOverriddenControllerTest ProxyOverriddenControllerTest +#else +#define MAYBE_ProxyOverriddenControllerTest DISABLED_ProxyOverriddenControllerTest +#endif + +TEST_F(ExtensionMessageBubbleTest, MAYBE_ProxyOverriddenControllerTest) { + Init(); + ExtensionPrefs* prefs = ExtensionPrefs::Get(profile()); + // Load two extensions overriding proxy and one overriding something + // unrelated (to check for interference). Extension 2 should still win + // on the proxy setting. + ASSERT_TRUE(LoadExtensionOverridingProxy("1", kId1, Manifest::UNPACKED)); + ASSERT_TRUE(LoadExtensionOverridingProxy("2", kId2, Manifest::UNPACKED)); + ASSERT_TRUE(LoadExtensionOverridingStart("3", kId3, Manifest::UNPACKED)); + + // The bubble will not show if the extension was installed in the last 7 days + // so we artificially set the install time to simulate an old install during + // testing. + base::Time old_enough = base::Time::Now() - base::TimeDelta::FromDays(8); + SetInstallTime(kId1, old_enough, prefs); + SetInstallTime(kId2, base::Time::Now(), prefs); + SetInstallTime(kId3, old_enough, prefs); + + scoped_ptr<TestProxyOverriddenBubbleController> controller( + new TestProxyOverriddenBubbleController(profile())); + + // The second extension is too new to warn about. + EXPECT_FALSE(controller->ShouldShow(kId1)); + EXPECT_FALSE(controller->ShouldShow(kId2)); + // Lets make it old enough. + SetInstallTime(kId2, old_enough, prefs); + + // The list will contain one enabled unpacked extension (ext 2). + EXPECT_TRUE(controller->ShouldShow(kId2)); + EXPECT_FALSE(controller->ShouldShow(kId3)); + std::vector<base::string16> override_extensions = + controller->GetExtensionList(); + ASSERT_EQ(1U, override_extensions.size()); + EXPECT_EQ(base::ASCIIToUTF16("Extension 2"), override_extensions[0]); + EXPECT_EQ(0U, controller->link_click_count()); + EXPECT_EQ(0U, controller->dismiss_click_count()); + EXPECT_EQ(0U, controller->action_click_count()); + + // Simulate showing the bubble and dismissing it. + FakeExtensionMessageBubble bubble; + bubble.set_action_on_show( + FakeExtensionMessageBubble::BUBBLE_ACTION_CLICK_DISMISS_BUTTON); + controller->Show(&bubble); + EXPECT_EQ(0U, controller->link_click_count()); + EXPECT_EQ(0U, controller->action_click_count()); + EXPECT_EQ(1U, controller->dismiss_click_count()); + // No extension should have become disabled. + ExtensionRegistry* registry = ExtensionRegistry::Get(profile()); + EXPECT_TRUE(registry->enabled_extensions().GetByID(kId1) != NULL); + EXPECT_TRUE(registry->enabled_extensions().GetByID(kId2) != NULL); + EXPECT_TRUE(registry->enabled_extensions().GetByID(kId3) != NULL); + // Only extension 2 should have been acknowledged. + EXPECT_FALSE(prefs->HasProxyOverriddenBubbleBeenAcknowledged(kId1)); + EXPECT_TRUE(prefs->HasProxyOverriddenBubbleBeenAcknowledged(kId2)); + EXPECT_FALSE(prefs->HasProxyOverriddenBubbleBeenAcknowledged(kId3)); + // Clean up after ourselves. + prefs->SetProxyOverriddenBubbleBeenAcknowledged(kId2, false); + + // Simulate clicking the learn more link to dismiss it. + bubble.set_action_on_show( + FakeExtensionMessageBubble::BUBBLE_ACTION_CLICK_LINK); + controller.reset(new TestProxyOverriddenBubbleController(profile())); + EXPECT_TRUE(controller->ShouldShow(kId2)); + controller->Show(&bubble); + EXPECT_EQ(1U, controller->link_click_count()); + EXPECT_EQ(0U, controller->action_click_count()); + EXPECT_EQ(0U, controller->dismiss_click_count()); + // No extension should have become disabled. + EXPECT_TRUE(registry->enabled_extensions().GetByID(kId1) != NULL); + EXPECT_TRUE(registry->enabled_extensions().GetByID(kId2) != NULL); + EXPECT_TRUE(registry->enabled_extensions().GetByID(kId3) != NULL); + // Only extension 2 should have been acknowledged. + EXPECT_FALSE(prefs->HasProxyOverriddenBubbleBeenAcknowledged(kId1)); + EXPECT_TRUE(prefs->HasProxyOverriddenBubbleBeenAcknowledged(kId2)); + EXPECT_FALSE(prefs->HasProxyOverriddenBubbleBeenAcknowledged(kId3)); + // Clean up after ourselves. + prefs->SetProxyOverriddenBubbleBeenAcknowledged(kId2, false); + + // Do it again, but now opt to disable the extension. + bubble.set_action_on_show( + FakeExtensionMessageBubble::BUBBLE_ACTION_CLICK_ACTION_BUTTON); + controller.reset(new TestProxyOverriddenBubbleController(profile())); + EXPECT_TRUE(controller->ShouldShow(kId2)); + override_extensions = controller->GetExtensionList(); + EXPECT_EQ(1U, override_extensions.size()); + controller->Show(&bubble); // Simulate showing the bubble. + EXPECT_EQ(0U, controller->link_click_count()); + EXPECT_EQ(1U, controller->action_click_count()); + EXPECT_EQ(0U, controller->dismiss_click_count()); + // Only extension 2 should have become disabled. + EXPECT_TRUE(registry->enabled_extensions().GetByID(kId1) != NULL); + EXPECT_TRUE(registry->disabled_extensions().GetByID(kId2) != NULL); + EXPECT_TRUE(registry->enabled_extensions().GetByID(kId3) != NULL); + // No extension should have been acknowledged (it got disabled). + EXPECT_FALSE(prefs->HasProxyOverriddenBubbleBeenAcknowledged(kId1)); + EXPECT_FALSE(prefs->HasProxyOverriddenBubbleBeenAcknowledged(kId2)); + EXPECT_FALSE(prefs->HasProxyOverriddenBubbleBeenAcknowledged(kId3)); + + // Clean up after ourselves. + service_->UninstallExtension(kId1, false, NULL); + service_->UninstallExtension(kId2, false, NULL); + service_->UninstallExtension(kId3, false, NULL); +} + } // namespace extensions diff --git a/chrome/browser/extensions/ntp_overridden_bubble_controller.cc b/chrome/browser/extensions/ntp_overridden_bubble_controller.cc index d832ce4..6abec00 100644 --- a/chrome/browser/extensions/ntp_overridden_bubble_controller.cc +++ b/chrome/browser/extensions/ntp_overridden_bubble_controller.cc @@ -36,7 +36,8 @@ class NtpOverriddenBubbleDelegate user_action) OVERRIDE; virtual void PerformAction(const extensions::ExtensionIdList& list) OVERRIDE; virtual base::string16 GetTitle() const OVERRIDE; - virtual base::string16 GetMessageBody() const OVERRIDE; + virtual base::string16 GetMessageBody( + bool anchored_to_browser_action) const OVERRIDE; virtual base::string16 GetOverflowText( const base::string16& overflow_count) const OVERRIDE; virtual base::string16 GetLearnMoreLabel() const OVERRIDE; @@ -113,7 +114,8 @@ base::string16 NtpOverriddenBubbleDelegate::GetTitle() const { IDS_EXTENSIONS_NTP_CONTROLLED_TITLE_HOME_PAGE_BUBBLE); } -base::string16 NtpOverriddenBubbleDelegate::GetMessageBody() const { +base::string16 NtpOverriddenBubbleDelegate::GetMessageBody( + bool anchored_to_browser_action) const { base::string16 body = l10n_util::GetStringUTF16(IDS_EXTENSIONS_NTP_CONTROLLED_FIRST_LINE); body += l10n_util::GetStringUTF16( diff --git a/chrome/browser/extensions/proxy_overridden_bubble_controller.cc b/chrome/browser/extensions/proxy_overridden_bubble_controller.cc new file mode 100644 index 0000000..e8ce9ae --- /dev/null +++ b/chrome/browser/extensions/proxy_overridden_bubble_controller.cc @@ -0,0 +1,217 @@ +// Copyright 2014 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/extensions/proxy_overridden_bubble_controller.h" + +#include "base/metrics/histogram.h" +#include "chrome/browser/extensions/extension_service.h" +#include "chrome/browser/extensions/extension_toolbar_model.h" +#include "chrome/browser/extensions/settings_api_helpers.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/common/url_constants.h" +#include "extensions/browser/extension_registry.h" +#include "extensions/browser/extension_system.h" +#include "grit/generated_resources.h" +#include "ui/base/l10n/l10n_util.h" + +namespace extensions { + +namespace { + +// The minimum time to wait (since the extension was installed) before notifying +// the user about it. +const int kDaysSinceInstallMin = 7; + +//////////////////////////////////////////////////////////////////////////////// +// ProxyOverriddenBubbleDelegate + +class ProxyOverriddenBubbleDelegate + : public ExtensionMessageBubbleController::Delegate { + public: + ProxyOverriddenBubbleDelegate(ExtensionService* service, Profile* profile); + virtual ~ProxyOverriddenBubbleDelegate(); + + // ExtensionMessageBubbleController::Delegate methods. + virtual bool ShouldIncludeExtension(const std::string& extension_id) OVERRIDE; + virtual void AcknowledgeExtension( + const std::string& extension_id, + ExtensionMessageBubbleController::BubbleAction + user_action) OVERRIDE; + virtual void PerformAction(const ExtensionIdList& list) OVERRIDE; + virtual void OnClose() OVERRIDE; + virtual base::string16 GetTitle() const OVERRIDE; + virtual base::string16 GetMessageBody( + bool anchored_to_browser_action) const OVERRIDE; + virtual base::string16 GetOverflowText( + const base::string16& overflow_count) const OVERRIDE; + virtual base::string16 GetLearnMoreLabel() const OVERRIDE; + virtual GURL GetLearnMoreUrl() const OVERRIDE; + virtual base::string16 GetActionButtonLabel() const OVERRIDE; + virtual base::string16 GetDismissButtonLabel() const OVERRIDE; + virtual bool ShouldShowExtensionList() const OVERRIDE; + virtual void RestrictToSingleExtension( + const std::string& extension_id) OVERRIDE; + virtual void LogExtensionCount(size_t count) OVERRIDE; + virtual void LogAction( + ExtensionMessageBubbleController::BubbleAction + action) OVERRIDE; + + private: + // Our extension service. Weak, not owned by us. + ExtensionService* service_; + + // A weak pointer to the profile we are associated with. Not owned by us. + Profile* profile_; + + // The ID of the extension we are showing the bubble for. + std::string extension_id_; + + DISALLOW_COPY_AND_ASSIGN(ProxyOverriddenBubbleDelegate); +}; + +ProxyOverriddenBubbleDelegate::ProxyOverriddenBubbleDelegate( + ExtensionService* service, + Profile* profile) + : service_(service), profile_(profile) {} + +ProxyOverriddenBubbleDelegate::~ProxyOverriddenBubbleDelegate() {} + +bool ProxyOverriddenBubbleDelegate::ShouldIncludeExtension( + const std::string& extension_id) { + if (!extension_id_.empty() && extension_id_ != extension_id) + return false; + + const Extension* extension = + ExtensionRegistry::Get(profile_)->enabled_extensions().GetByID( + extension_id); + if (!extension) + return false; // The extension provided is no longer enabled. + + const Extension* overriding = GetExtensionOverridingProxy(profile_); + if (!overriding || overriding->id() != extension_id) + return false; + + ExtensionPrefs* prefs = ExtensionPrefs::Get(profile_); + base::TimeDelta since_install = + base::Time::Now() - prefs->GetInstallTime(extension->id()); + if (since_install.InDays() < kDaysSinceInstallMin) + return false; + + if (ExtensionPrefs::Get(profile_)->HasProxyOverriddenBubbleBeenAcknowledged( + extension_id)) + return false; + + return true; +} + +void ProxyOverriddenBubbleDelegate::AcknowledgeExtension( + const std::string& extension_id, + ExtensionMessageBubbleController::BubbleAction user_action) { + if (user_action != ExtensionMessageBubbleController::ACTION_EXECUTE) { + ExtensionPrefs::Get(profile_)->SetProxyOverriddenBubbleBeenAcknowledged( + extension_id, true); + } +} + +void ProxyOverriddenBubbleDelegate::PerformAction(const ExtensionIdList& list) { + for (size_t i = 0; i < list.size(); ++i) + service_->DisableExtension(list[i], Extension::DISABLE_USER_ACTION); +} + +void ProxyOverriddenBubbleDelegate::OnClose() { + ExtensionToolbarModel* toolbar_model = + ExtensionToolbarModel::Get(profile_); + if (toolbar_model) + toolbar_model->StopHighlighting(); +} + +base::string16 ProxyOverriddenBubbleDelegate::GetTitle() const { + return l10n_util::GetStringUTF16( + IDS_EXTENSIONS_PROXY_CONTROLLED_TITLE_HOME_PAGE_BUBBLE); +} + +base::string16 ProxyOverriddenBubbleDelegate::GetMessageBody( + bool anchored_to_browser_action) const { + if (anchored_to_browser_action) { + return l10n_util::GetStringUTF16( + IDS_EXTENSIONS_PROXY_CONTROLLED_FIRST_LINE_EXTENSION_SPECIFIC); + } else { + return l10n_util::GetStringUTF16( + IDS_EXTENSIONS_PROXY_CONTROLLED_FIRST_LINE); + } +} + +base::string16 ProxyOverriddenBubbleDelegate::GetOverflowText( + const base::string16& overflow_count) const { + // Does not have more than one extension in the list at a time. + NOTREACHED(); + return base::string16(); +} + +base::string16 ProxyOverriddenBubbleDelegate::GetLearnMoreLabel() const { + return l10n_util::GetStringUTF16(IDS_LEARN_MORE); +} + +GURL ProxyOverriddenBubbleDelegate::GetLearnMoreUrl() const { + return GURL(chrome::kExtensionControlledSettingLearnMoreURL); +} + +base::string16 ProxyOverriddenBubbleDelegate::GetActionButtonLabel() const { + return l10n_util::GetStringUTF16(IDS_EXTENSION_CONTROLLED_RESTORE_SETTINGS); +} + +base::string16 ProxyOverriddenBubbleDelegate::GetDismissButtonLabel() const { + return l10n_util::GetStringUTF16(IDS_EXTENSION_CONTROLLED_KEEP_CHANGES); +} + +bool ProxyOverriddenBubbleDelegate::ShouldShowExtensionList() const { + return false; +} + +void ProxyOverriddenBubbleDelegate::RestrictToSingleExtension( + const std::string& extension_id) { + extension_id_ = extension_id; +} + +void ProxyOverriddenBubbleDelegate::LogExtensionCount(size_t count) { + UMA_HISTOGRAM_COUNTS_100("ProxyOverriddenBubble.ExtensionCount", count); +} + +void ProxyOverriddenBubbleDelegate::LogAction( + ExtensionMessageBubbleController::BubbleAction action) { + UMA_HISTOGRAM_ENUMERATION("ProxyOverriddenBubble.UserSelection", + action, + ExtensionMessageBubbleController::ACTION_BOUNDARY); +} + +} // namespace + +//////////////////////////////////////////////////////////////////////////////// +// ProxyOverriddenBubbleController + +ProxyOverriddenBubbleController::ProxyOverriddenBubbleController( + Profile* profile) + : ExtensionMessageBubbleController( + new ProxyOverriddenBubbleDelegate( + ExtensionSystem::Get(profile)->extension_service(), + profile), + profile), + profile_(profile) {} + +ProxyOverriddenBubbleController::~ProxyOverriddenBubbleController() {} + +bool ProxyOverriddenBubbleController::ShouldShow( + const std::string& extension_id) { + if (!delegate()->ShouldIncludeExtension(extension_id)) + return false; + + delegate()->RestrictToSingleExtension(extension_id); + return true; +} + +bool ProxyOverriddenBubbleController::CloseOnDeactivate() { + return true; +} + +} // namespace extensions diff --git a/chrome/browser/extensions/proxy_overridden_bubble_controller.h b/chrome/browser/extensions/proxy_overridden_bubble_controller.h new file mode 100644 index 0000000..be2e0fc --- /dev/null +++ b/chrome/browser/extensions/proxy_overridden_bubble_controller.h @@ -0,0 +1,39 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_EXTENSIONS_PROXY_OVERRIDDEN_BUBBLE_CONTROLLER_H_ +#define CHROME_BROWSER_EXTENSIONS_PROXY_OVERRIDDEN_BUBBLE_CONTROLLER_H_ + +#include <string> + +#include "base/macros.h" +#include "chrome/browser/extensions/extension_message_bubble_controller.h" + +class Profile; + +namespace extensions { + +class ProxyOverriddenBubbleController + : public ExtensionMessageBubbleController { + public: + explicit ProxyOverriddenBubbleController(Profile* profile); + virtual ~ProxyOverriddenBubbleController(); + + // Whether the controller knows that we should show the bubble for extension + // with |extension_id|. Returns true if so. + bool ShouldShow(const std::string& extension_id); + + // ExtensionMessageBubbleController: + virtual bool CloseOnDeactivate() OVERRIDE; + + private: + // A weak pointer to the profile we are associated with. Not owned by us. + Profile* profile_; + + DISALLOW_COPY_AND_ASSIGN(ProxyOverriddenBubbleController); +}; + +} // namespace extensions + +#endif // CHROME_BROWSER_EXTENSIONS_PROXY_OVERRIDDEN_BUBBLE_CONTROLLER_H_ diff --git a/chrome/browser/extensions/settings_api_bubble_controller.cc b/chrome/browser/extensions/settings_api_bubble_controller.cc index 0b35388..79d7eb7 100644 --- a/chrome/browser/extensions/settings_api_bubble_controller.cc +++ b/chrome/browser/extensions/settings_api_bubble_controller.cc @@ -6,6 +6,7 @@ #include "base/metrics/histogram.h" #include "chrome/browser/extensions/extension_service.h" +#include "chrome/browser/extensions/extension_toolbar_model.h" #include "chrome/browser/extensions/settings_api_helpers.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/startup/startup_browser_creator.h" @@ -18,9 +19,7 @@ #include "grit/generated_resources.h" #include "ui/base/l10n/l10n_util.h" -using extensions::ExtensionMessageBubbleController; -using extensions::SettingsApiBubbleController; -using extensions::SettingsOverrides; +namespace extensions { namespace { @@ -28,22 +27,23 @@ namespace { // SettingsApiBubbleDelegate class SettingsApiBubbleDelegate - : public extensions::ExtensionMessageBubbleController::Delegate { + : public ExtensionMessageBubbleController::Delegate { public: explicit SettingsApiBubbleDelegate(ExtensionService* service, Profile* profile, - extensions::SettingsApiOverrideType type); + SettingsApiOverrideType type); virtual ~SettingsApiBubbleDelegate(); // ExtensionMessageBubbleController::Delegate methods. virtual bool ShouldIncludeExtension(const std::string& extension_id) OVERRIDE; virtual void AcknowledgeExtension( const std::string& extension_id, - extensions::ExtensionMessageBubbleController::BubbleAction user_action) - OVERRIDE; - virtual void PerformAction(const extensions::ExtensionIdList& list) OVERRIDE; + ExtensionMessageBubbleController::BubbleAction user_action) OVERRIDE; + virtual void PerformAction(const ExtensionIdList& list) OVERRIDE; + virtual void OnClose() OVERRIDE; virtual base::string16 GetTitle() const OVERRIDE; - virtual base::string16 GetMessageBody() const OVERRIDE; + virtual base::string16 GetMessageBody( + bool anchored_to_browser_action) const OVERRIDE; virtual base::string16 GetOverflowText( const base::string16& overflow_count) const OVERRIDE; virtual base::string16 GetLearnMoreLabel() const OVERRIDE; @@ -53,8 +53,7 @@ class SettingsApiBubbleDelegate virtual bool ShouldShowExtensionList() const OVERRIDE; virtual void LogExtensionCount(size_t count) OVERRIDE; virtual void LogAction( - extensions::ExtensionMessageBubbleController::BubbleAction action) - OVERRIDE; + ExtensionMessageBubbleController::BubbleAction action) OVERRIDE; private: // Our extension service. Weak, not owned by us. @@ -66,7 +65,7 @@ class SettingsApiBubbleDelegate // The type of settings override this bubble will report on. This can be, for // example, a bubble to notify the user that the search engine has been // changed by an extension (or homepage/startup pages/etc). - extensions::SettingsApiOverrideType type_; + SettingsApiOverrideType type_; // The ID of the extension we are showing the bubble for. std::string extension_id_; @@ -77,34 +76,33 @@ class SettingsApiBubbleDelegate SettingsApiBubbleDelegate::SettingsApiBubbleDelegate( ExtensionService* service, Profile* profile, - extensions::SettingsApiOverrideType type) + SettingsApiOverrideType type) : service_(service), profile_(profile), type_(type) {} SettingsApiBubbleDelegate::~SettingsApiBubbleDelegate() {} bool SettingsApiBubbleDelegate::ShouldIncludeExtension( const std::string& extension_id) { - using extensions::ExtensionRegistry; ExtensionRegistry* registry = ExtensionRegistry::Get(profile_); - const extensions::Extension* extension = + const Extension* extension = registry->GetExtensionById(extension_id, ExtensionRegistry::ENABLED); if (!extension) return false; // The extension provided is no longer enabled. - extensions::ExtensionPrefs* prefs = extensions::ExtensionPrefs::Get(profile_); + ExtensionPrefs* prefs = ExtensionPrefs::Get(profile_); if (prefs->HasSettingsApiBubbleBeenAcknowledged(extension_id)) return false; - const extensions::Extension* override = NULL; + const Extension* override = NULL; switch (type_) { - case extensions::BUBBLE_TYPE_HOME_PAGE: - override = extensions::OverridesHomepage(profile_, NULL); + case BUBBLE_TYPE_HOME_PAGE: + override = GetExtensionOverridingHomepage(profile_, NULL); break; - case extensions::BUBBLE_TYPE_STARTUP_PAGES: - override = extensions::OverridesStartupPages(profile_, NULL); + case BUBBLE_TYPE_STARTUP_PAGES: + override = GetExtensionOverridingStartupPages(profile_, NULL); break; - case extensions::BUBBLE_TYPE_SEARCH_ENGINE: - override = extensions::OverridesSearchEngine(profile_, NULL); + case BUBBLE_TYPE_SEARCH_ENGINE: + override = GetExtensionOverridingSearchEngine(profile_, NULL); break; } @@ -119,29 +117,32 @@ void SettingsApiBubbleDelegate::AcknowledgeExtension( const std::string& extension_id, ExtensionMessageBubbleController::BubbleAction user_action) { if (user_action != ExtensionMessageBubbleController::ACTION_EXECUTE) { - extensions::ExtensionPrefs* prefs = - extensions::ExtensionPrefs::Get(profile_); + ExtensionPrefs* prefs = ExtensionPrefs::Get(profile_); prefs->SetSettingsApiBubbleBeenAcknowledged(extension_id, true); } } -void SettingsApiBubbleDelegate::PerformAction( - const extensions::ExtensionIdList& list) { +void SettingsApiBubbleDelegate::PerformAction(const ExtensionIdList& list) { for (size_t i = 0; i < list.size(); ++i) { - service_->DisableExtension(list[i], - extensions::Extension::DISABLE_USER_ACTION); + service_->DisableExtension(list[i], Extension::DISABLE_USER_ACTION); } } +void SettingsApiBubbleDelegate::OnClose() { + ExtensionToolbarModel* toolbar_model = ExtensionToolbarModel::Get(profile_); + if (toolbar_model) + toolbar_model->StopHighlighting(); +} + base::string16 SettingsApiBubbleDelegate::GetTitle() const { switch (type_) { - case extensions::BUBBLE_TYPE_HOME_PAGE: + case BUBBLE_TYPE_HOME_PAGE: return l10n_util::GetStringUTF16( IDS_EXTENSIONS_SETTINGS_API_TITLE_HOME_PAGE_BUBBLE); - case extensions::BUBBLE_TYPE_STARTUP_PAGES: + case BUBBLE_TYPE_STARTUP_PAGES: return l10n_util::GetStringUTF16( IDS_EXTENSIONS_SETTINGS_API_TITLE_STARTUP_PAGES_BUBBLE); - case extensions::BUBBLE_TYPE_SEARCH_ENGINE: + case BUBBLE_TYPE_SEARCH_ENGINE: return l10n_util::GetStringUTF16( IDS_EXTENSIONS_SETTINGS_API_TITLE_SEARCH_ENGINE_BUBBLE); } @@ -149,10 +150,10 @@ base::string16 SettingsApiBubbleDelegate::GetTitle() const { return base::string16(); } -base::string16 SettingsApiBubbleDelegate::GetMessageBody() const { - using extensions::ExtensionRegistry; +base::string16 SettingsApiBubbleDelegate::GetMessageBody( + bool anchored_to_browser_action) const { ExtensionRegistry* registry = ExtensionRegistry::Get(profile_); - const extensions::Extension* extension = + const Extension* extension = registry->GetExtensionById(extension_id_, ExtensionRegistry::ENABLED); const SettingsOverrides* settings = extension ? SettingsOverrides::Get(extension) : NULL; @@ -167,7 +168,7 @@ base::string16 SettingsApiBubbleDelegate::GetMessageBody() const { base::string16 body; switch (type_) { - case extensions::BUBBLE_TYPE_HOME_PAGE: + case BUBBLE_TYPE_HOME_PAGE: body = l10n_util::GetStringUTF16( IDS_EXTENSIONS_SETTINGS_API_FIRST_LINE_HOME_PAGE); if (startup_change && search_change) { @@ -181,7 +182,7 @@ base::string16 SettingsApiBubbleDelegate::GetMessageBody() const { IDS_EXTENSIONS_SETTINGS_API_SECOND_LINE_SEARCH_ENGINE); } break; - case extensions::BUBBLE_TYPE_STARTUP_PAGES: + case BUBBLE_TYPE_STARTUP_PAGES: body = l10n_util::GetStringUTF16( IDS_EXTENSIONS_SETTINGS_API_FIRST_LINE_START_PAGES); if (home_change && search_change) { @@ -195,7 +196,7 @@ base::string16 SettingsApiBubbleDelegate::GetMessageBody() const { IDS_EXTENSIONS_SETTINGS_API_SECOND_LINE_SEARCH_ENGINE); } break; - case extensions::BUBBLE_TYPE_SEARCH_ENGINE: + case BUBBLE_TYPE_SEARCH_ENGINE: body = l10n_util::GetStringUTF16( IDS_EXTENSIONS_SETTINGS_API_FIRST_LINE_SEARCH_ENGINE); if (startup_change && home_change) { @@ -249,19 +250,19 @@ void SettingsApiBubbleDelegate::LogExtensionCount(size_t count) { void SettingsApiBubbleDelegate::LogAction( ExtensionMessageBubbleController::BubbleAction action) { switch (type_) { - case extensions::BUBBLE_TYPE_HOME_PAGE: + case BUBBLE_TYPE_HOME_PAGE: UMA_HISTOGRAM_ENUMERATION( "ExtensionOverrideBubble.SettingsApiUserSelectionHomePage", action, ExtensionMessageBubbleController::ACTION_BOUNDARY); break; - case extensions::BUBBLE_TYPE_STARTUP_PAGES: + case BUBBLE_TYPE_STARTUP_PAGES: UMA_HISTOGRAM_ENUMERATION( "ExtensionOverrideBubble.SettingsApiUserSelectionStartupPage", action, ExtensionMessageBubbleController::ACTION_BOUNDARY); break; - case extensions::BUBBLE_TYPE_SEARCH_ENGINE: + case BUBBLE_TYPE_SEARCH_ENGINE: UMA_HISTOGRAM_ENUMERATION( "ExtensionOverrideBubble.SettingsApiUserSelectionSearchEngine", action, @@ -272,8 +273,6 @@ void SettingsApiBubbleDelegate::LogAction( } // namespace -namespace extensions { - //////////////////////////////////////////////////////////////////////////////// // SettingsApiBubbleController @@ -292,7 +291,7 @@ SettingsApiBubbleController::SettingsApiBubbleController( SettingsApiBubbleController::~SettingsApiBubbleController() {} bool SettingsApiBubbleController::ShouldShow(const std::string& extension_id) { - extensions::ExtensionPrefs* prefs = extensions::ExtensionPrefs::Get(profile_); + ExtensionPrefs* prefs = ExtensionPrefs::Get(profile_); if (prefs->HasSettingsApiBubbleBeenAcknowledged(extension_id)) return false; diff --git a/chrome/browser/extensions/settings_api_helpers.cc b/chrome/browser/extensions/settings_api_helpers.cc index 839098cb..2c087cd 100644 --- a/chrome/browser/extensions/settings_api_helpers.cc +++ b/chrome/browser/extensions/settings_api_helpers.cc @@ -6,23 +6,24 @@ #include "chrome/browser/extensions/api/preference/preference_api.h" #include "chrome/common/pref_names.h" +#include "extensions/browser/extension_pref_value_map.h" +#include "extensions/browser/extension_pref_value_map_factory.h" #include "extensions/browser/extension_registry.h" #include "extensions/common/extension_set.h" namespace extensions { -const extensions::SettingsOverrides* FindOverridingExtension( +const SettingsOverrides* FindOverridingExtension( content::BrowserContext* browser_context, SettingsApiOverrideType type, const Extension** extension) { - const extensions::ExtensionSet& extensions = - extensions::ExtensionRegistry::Get(browser_context)->enabled_extensions(); + const ExtensionSet& extensions = + ExtensionRegistry::Get(browser_context)->enabled_extensions(); - for (extensions::ExtensionSet::const_iterator it = extensions.begin(); + for (ExtensionSet::const_iterator it = extensions.begin(); it != extensions.end(); ++it) { - const extensions::SettingsOverrides* settings = - extensions::SettingsOverrides::Get(*it); + const SettingsOverrides* settings = SettingsOverrides::Get(*it); if (settings) { if (type == BUBBLE_TYPE_HOME_PAGE && !settings->homepage) continue; @@ -59,10 +60,10 @@ const extensions::SettingsOverrides* FindOverridingExtension( return NULL; } -const Extension* OverridesHomepage(content::BrowserContext* browser_context, - GURL* home_page_url) { - const extensions::Extension* extension = NULL; - const extensions::SettingsOverrides* settings = +const Extension* GetExtensionOverridingHomepage( + content::BrowserContext* browser_context, GURL* home_page_url) { + const Extension* extension = NULL; + const SettingsOverrides* settings = FindOverridingExtension( browser_context, BUBBLE_TYPE_HOME_PAGE, &extension); @@ -71,10 +72,11 @@ const Extension* OverridesHomepage(content::BrowserContext* browser_context, return extension; } -const Extension* OverridesStartupPages(content::BrowserContext* browser_context, - std::vector<GURL>* startup_pages) { - const extensions::Extension* extension = NULL; - const extensions::SettingsOverrides* settings = +const Extension* GetExtensionOverridingStartupPages( + content::BrowserContext* browser_context, + std::vector<GURL>* startup_pages) { + const Extension* extension = NULL; + const SettingsOverrides* settings = FindOverridingExtension( browser_context, BUBBLE_TYPE_STARTUP_PAGES, &extension); if (settings && startup_pages) { @@ -87,12 +89,12 @@ const Extension* OverridesStartupPages(content::BrowserContext* browser_context, return extension; } -const Extension* OverridesSearchEngine( +const Extension* GetExtensionOverridingSearchEngine( content::BrowserContext* browser_context, api::manifest_types::ChromeSettingsOverrides::Search_provider* search_provider) { - const extensions::Extension* extension = NULL; - const extensions::SettingsOverrides* settings = + const Extension* extension = NULL; + const SettingsOverrides* settings = FindOverridingExtension( browser_context, BUBBLE_TYPE_SEARCH_ENGINE, &extension); if (settings && search_provider) @@ -100,4 +102,18 @@ const Extension* OverridesSearchEngine( return extension; } +const Extension* GetExtensionOverridingProxy( + content::BrowserContext* browser_context) { + ExtensionPrefValueMap* extension_prefs_value_map = + ExtensionPrefValueMapFactory::GetForBrowserContext(browser_context); + if (!extension_prefs_value_map) + return NULL; // Can be null during testing. + std::string extension_id = + extension_prefs_value_map->GetExtensionControllingPref(prefs::kProxy); + if (extension_id.empty()) + return NULL; + return ExtensionRegistry::Get(browser_context)->GetExtensionById( + extension_id, ExtensionRegistry::ENABLED); +} + } // namespace extensions diff --git a/chrome/browser/extensions/settings_api_helpers.h b/chrome/browser/extensions/settings_api_helpers.h index db2ba36..866fbb1 100644 --- a/chrome/browser/extensions/settings_api_helpers.h +++ b/chrome/browser/extensions/settings_api_helpers.h @@ -24,25 +24,35 @@ const extensions::SettingsOverrides* FindOverridingExtension( const Extension** extension); // Returns which extension is overriding the homepage in a given -// |browser_context|. |home_page_url|, if non-NULL, will contain the home_page -// value the extension has set. -const Extension* OverridesHomepage(content::BrowserContext* browser_context, - GURL* home_page_url); +// |browser_context| or NULL if no extension is overriding the homepage. +// |home_page_url|, if non-NULL, will contain the home_page value the extension +// has set. +const Extension* GetExtensionOverridingHomepage( + content::BrowserContext* browser_context, + GURL* home_page_url); // Returns which extension is overriding the homepage in a given -// |browser_context|. |startup_pages|, if non-NULL, will contain the vector of -// startup page URLs the extension has set. -const Extension* OverridesStartupPages(content::BrowserContext* browser_context, - std::vector<GURL>* startup_pages); +// |browser_context| or NULL if no extension is overriding the startup pages. +// |startup_pages|, if non-NULL, will contain the vector of startup page URLs +// the extension has set. +const Extension* GetExtensionOverridingStartupPages( + content::BrowserContext* browser_context, + std::vector<GURL>* startup_pages); // Returns which extension is overriding the search engine in a given -// |browser_context|. |search_provider|, if non-NULL, will contain the search -// provider the extension has set. -const Extension* OverridesSearchEngine( +// |browser_context| or NULL if no extension is overriding the search engine. +// |search_provider|, if non-NULL, will contain the search provider the +// extension has set. +const Extension* GetExtensionOverridingSearchEngine( content::BrowserContext* browser_context, api::manifest_types::ChromeSettingsOverrides::Search_provider* search_provider); +// Returns which extension is overriding the proxy in a given |browser_context| +// or NULL if no extension is overriding the proxy. +const Extension* GetExtensionOverridingProxy( + content::BrowserContext* browser_context); + } // namespace extensions #endif // CHROME_BROWSER_EXTENSIONS_SETTINGS_API_HELPERS_H_ diff --git a/chrome/browser/extensions/suspicious_extension_bubble_controller.cc b/chrome/browser/extensions/suspicious_extension_bubble_controller.cc index 64803a0..c0a48d1 100644 --- a/chrome/browser/extensions/suspicious_extension_bubble_controller.cc +++ b/chrome/browser/extensions/suspicious_extension_bubble_controller.cc @@ -42,7 +42,8 @@ class SuspiciousExtensionBubbleDelegate ExtensionMessageBubbleController::BubbleAction user_action) OVERRIDE; virtual void PerformAction(const extensions::ExtensionIdList& list) OVERRIDE; virtual base::string16 GetTitle() const OVERRIDE; - virtual base::string16 GetMessageBody() const OVERRIDE; + virtual base::string16 GetMessageBody( + bool anchored_to_browser_action) const OVERRIDE; virtual base::string16 GetOverflowText( const base::string16& overflow_count) const OVERRIDE; virtual base::string16 GetLearnMoreLabel() const OVERRIDE; @@ -98,7 +99,8 @@ base::string16 SuspiciousExtensionBubbleDelegate::GetTitle() const { return l10n_util::GetStringUTF16(IDS_EXTENSIONS_UNSUPPORTED_DISABLED_TITLE); } -base::string16 SuspiciousExtensionBubbleDelegate::GetMessageBody() const { +base::string16 SuspiciousExtensionBubbleDelegate::GetMessageBody( + bool anchored_to_browser_action) const { return l10n_util::GetStringFUTF16(IDS_EXTENSIONS_UNSUPPORTED_DISABLED_BODY, l10n_util::GetStringUTF16(IDS_EXTENSION_WEB_STORE_TITLE)); } diff --git a/chrome/browser/resources/options/browser_options.html b/chrome/browser/resources/options/browser_options.html index 345057a..83ac8f5 100644 --- a/chrome/browser/resources/options/browser_options.html +++ b/chrome/browser/resources/options/browser_options.html @@ -29,6 +29,11 @@ <include src="sync_section.html"> <include src="startup_section.html"> </if> + <section id="proxy-section" hidden> + <h3 i18n-content="sectionTitleProxy"></h3> + <div id="proxy-section-content"></div> + </section> + <section> <h3 i18n-content="sectionTitleAppearance"></h3> <div class="settings-row"> @@ -556,7 +561,9 @@ <section id="network-section"> <h3 i18n-content="advancedSectionTitleNetwork"></h3> <div> - <span id="proxiesLabel" class="settings-row"></span> + <span id="proxiesLabel" + class="settings-row" + i18n-content="proxiesLabelSystem"></span> <div class="settings-row"> <button id="proxiesConfigureButton" i18n-content="proxiesConfigureButton"></button> diff --git a/chrome/browser/resources/options/browser_options.js b/chrome/browser/resources/options/browser_options.js index 59fe9eb..c5fd816 100644 --- a/chrome/browser/resources/options/browser_options.js +++ b/chrome/browser/resources/options/browser_options.js @@ -573,6 +573,9 @@ cr.define('options', function() { this.addExtensionControlledBox_('newtab-section-content', 'newtab-controlled', false); + this.addExtensionControlledBox_('proxy-section-content', + 'proxy-controlled', + true); document.body.addEventListener('click', function(e) { var button = findAncestor(e.target, function(el) { @@ -1508,10 +1511,14 @@ cr.define('options', function() { }, /** - * Set the enabled state for the proxy settings button. + * Set the enabled state for the proxy settings button and its associated + * message when extension controlled. + * @param {boolean} disabled Whether the button should be disabled. + * @param {boolean} extensionControlled Whether the proxy is extension + * controlled. * @private */ - setupProxySettingsSection_: function(disabled, extensionControlled) { + setupProxySettingsButton_: function(disabled, extensionControlled) { if (!cr.isChromeOS) { $('proxiesConfigureButton').disabled = disabled; $('proxiesLabel').textContent = @@ -1626,6 +1633,15 @@ cr.define('options', function() { 'newtab-controlled', details.newTabPage.id, details.newTabPage.name); + this.toggleExtensionControlledBox_('proxy-section-content', + 'proxy-controlled', + details.proxy.id, + details.proxy.name); + + // The proxy section contains just the warning box and nothing else, so + // if we're hiding the proxy warning box, we should also hide its header + // section. + $('proxy-section').hidden = details.proxy.id.length == 0; }, @@ -1794,7 +1810,7 @@ cr.define('options', function() { 'setThemesResetButtonEnabled', 'setVirtualKeyboardCheckboxState', 'setupPageZoomSelector', - 'setupProxySettingsSection', + 'setupProxySettingsButton', 'showBluetoothSettings', 'showCreateProfileError', 'showCreateProfileSuccess', diff --git a/chrome/browser/ui/cocoa/view_id_util_browsertest.mm b/chrome/browser/ui/cocoa/view_id_util_browsertest.mm index 033a15c..0c191d0 100644 --- a/chrome/browser/ui/cocoa/view_id_util_browsertest.mm +++ b/chrome/browser/ui/cocoa/view_id_util_browsertest.mm @@ -68,6 +68,7 @@ class ViewIDTest : public InProcessBrowserTest { // Mac implementation does not support following ids yet. if (i == VIEW_ID_STAR_BUTTON || i == VIEW_ID_CONTENTS_SPLIT || + i == VIEW_ID_BROWSER_ACTION || i == VIEW_ID_FEEDBACK_BUTTON || i == VIEW_ID_SCRIPT_BUBBLE || i == VIEW_ID_MIC_SEARCH_BUTTON || diff --git a/chrome/browser/ui/view_ids.h b/chrome/browser/ui/view_ids.h index f02b67a..f5ce29e 100644 --- a/chrome/browser/ui/view_ids.h +++ b/chrome/browser/ui/view_ids.h @@ -53,6 +53,7 @@ enum ViewID { VIEW_ID_STAR_BUTTON, VIEW_ID_APP_MENU, VIEW_ID_BROWSER_ACTION_TOOLBAR, + VIEW_ID_BROWSER_ACTION, VIEW_ID_FEEDBACK_BUTTON, VIEW_ID_OMNIBOX, VIEW_ID_SCRIPT_BUBBLE, diff --git a/chrome/browser/ui/views/extensions/extension_message_bubble_view.cc b/chrome/browser/ui/views/extensions/extension_message_bubble_view.cc index 43532db..41d48de 100644 --- a/chrome/browser/ui/views/extensions/extension_message_bubble_view.cc +++ b/chrome/browser/ui/views/extensions/extension_message_bubble_view.cc @@ -11,10 +11,12 @@ #include "chrome/browser/extensions/extension_action_manager.h" #include "chrome/browser/extensions/extension_message_bubble_controller.h" #include "chrome/browser/extensions/extension_service.h" +#include "chrome/browser/extensions/proxy_overridden_bubble_controller.h" #include "chrome/browser/extensions/settings_api_bubble_controller.h" #include "chrome/browser/extensions/settings_api_helpers.h" #include "chrome/browser/extensions/suspicious_extension_bubble_controller.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/view_ids.h" #include "chrome/browser/ui/views/frame/browser_view.h" #include "chrome/browser/ui/views/toolbar/browser_actions_container.h" #include "chrome/browser/ui/views/toolbar/browser_actions_container_observer.h" @@ -62,6 +64,7 @@ ExtensionMessageBubbleView::ExtensionMessageBubbleView( : BubbleDelegateView(anchor_view, arrow_location), weak_factory_(this), controller_(controller.Pass()), + anchor_view_(anchor_view), headline_(NULL), learn_more_(NULL), dismiss_button_(NULL), @@ -156,7 +159,8 @@ void ExtensionMessageBubbleView::Init() { views::Label* message = new views::Label(); message->SetMultiLine(true); message->SetHorizontalAlignment(gfx::ALIGN_LEFT); - message->SetText(delegate->GetMessageBody()); + message->SetText(delegate->GetMessageBody( + anchor_view_->id() == VIEW_ID_BROWSER_ACTION)); message->SizeToFit(views::Widget::GetLocalizedContentsWidth( IDS_EXTENSION_WIPEOUT_BUBBLE_WIDTH_CHARS)); layout->AddView(message); @@ -272,6 +276,7 @@ ExtensionMessageBubbleFactory::ExtensionMessageBubbleFactory( toolbar_view_(toolbar_view), shown_suspicious_extensions_bubble_(false), shown_startup_override_extensions_bubble_(false), + shown_proxy_override_extensions_bubble_(false), shown_dev_mode_extensions_bubble_(false), is_observing_(false), stage_(STAGE_START), @@ -304,6 +309,10 @@ void ExtensionMessageBubbleFactory::MaybeShow(views::View* anchor_view) { MaybeShowStartupOverrideExtensionsBubble(anchor_view)) return; + if (!shown_proxy_override_extensions_bubble_ && + MaybeShowProxyOverrideExtensionsBubble(anchor_view)) + return; + if (!shown_dev_mode_extensions_bubble_) MaybeShowDevModeExtensionsBubble(anchor_view); #endif // OS_WIN @@ -336,11 +345,11 @@ bool ExtensionMessageBubbleFactory::MaybeShowStartupOverrideExtensionsBubble( views::View* anchor_view) { #if !defined(OS_WIN) return false; -#endif - +#else DCHECK(!shown_startup_override_extensions_bubble_); - const Extension* extension = OverridesStartupPages(profile_, NULL); + const Extension* extension = + GetExtensionOverridingStartupPages(profile_, NULL); if (!extension) return false; @@ -351,15 +360,34 @@ bool ExtensionMessageBubbleFactory::MaybeShowStartupOverrideExtensionsBubble( return false; shown_startup_override_extensions_bubble_ = true; - SettingsApiBubbleController* weak_controller = settings_api_bubble.get(); - ExtensionMessageBubbleView* bubble_delegate = new ExtensionMessageBubbleView( - anchor_view, - views::BubbleBorder::TOP_RIGHT, - settings_api_bubble.PassAs<ExtensionMessageBubbleController>()); - views::BubbleDelegateView::CreateBubble(bubble_delegate); - weak_controller->Show(bubble_delegate); + PrepareToHighlightExtensions( + settings_api_bubble.PassAs<ExtensionMessageBubbleController>(), + anchor_view); + return true; +#endif +} +bool ExtensionMessageBubbleFactory::MaybeShowProxyOverrideExtensionsBubble( + views::View* anchor_view) { +#if !defined(OS_WIN) + return false; +#else + DCHECK(!shown_proxy_override_extensions_bubble_); + + const Extension* extension = GetExtensionOverridingProxy(profile_); + if (!extension) + return false; + + scoped_ptr<ProxyOverriddenBubbleController> proxy_bubble( + new ProxyOverriddenBubbleController(profile_)); + if (!proxy_bubble->ShouldShow(extension->id())) + return false; + + shown_proxy_override_extensions_bubble_ = true; + PrepareToHighlightExtensions( + proxy_bubble.PassAs<ExtensionMessageBubbleController>(), anchor_view); return true; +#endif } bool ExtensionMessageBubbleFactory::MaybeShowDevModeExtensionsBubble( @@ -375,23 +403,9 @@ bool ExtensionMessageBubbleFactory::MaybeShowDevModeExtensionsBubble( return false; shown_dev_mode_extensions_bubble_ = true; - - // We should be in the start stage (i.e., should not have a pending attempt to - // show a bubble). - DCHECK_EQ(stage_, STAGE_START); - - // Prepare to display and highlight the developer mode extensions before - // showing the bubble. Since this is an asynchronous process, set member - // variables for later use. - controller_ = dev_mode_extensions.Pass(); - anchor_view_ = anchor_view; - container_ = toolbar_view_->browser_actions(); - - if (container_->animating()) - MaybeObserve(); - else - HighlightDevModeExtensions(); - + PrepareToHighlightExtensions( + dev_mode_extensions.PassAs<ExtensionMessageBubbleController>(), + anchor_view); return true; } @@ -420,9 +434,9 @@ bool ExtensionMessageBubbleFactory::IsInitialProfileCheck(Profile* profile) { void ExtensionMessageBubbleFactory::OnBrowserActionsContainerAnimationEnded() { MaybeStopObserving(); if (stage_ == STAGE_START) { - HighlightDevModeExtensions(); + HighlightExtensions(); } else if (stage_ == STAGE_HIGHLIGHTED) { - ShowDevModeBubble(); + ShowHighlightingBubble(); } else { // We shouldn't be observing if we've completed the process. NOTREACHED(); Finish(); @@ -435,7 +449,26 @@ void ExtensionMessageBubbleFactory::OnBrowserActionsContainerDestroyed() { Finish(); } -void ExtensionMessageBubbleFactory::HighlightDevModeExtensions() { +void ExtensionMessageBubbleFactory::PrepareToHighlightExtensions( + scoped_ptr<ExtensionMessageBubbleController> controller, + views::View* anchor_view) { + // We should be in the start stage (i.e., should not have a pending attempt to + // show a bubble). + DCHECK_EQ(stage_, STAGE_START); + + // Prepare to display and highlight the extensions before showing the bubble. + // Since this is an asynchronous process, set member variables for later use. + controller_ = controller.Pass(); + anchor_view_ = anchor_view; + container_ = toolbar_view_->browser_actions(); + + if (container_->animating()) + MaybeObserve(); + else + HighlightExtensions(); +} + +void ExtensionMessageBubbleFactory::HighlightExtensions() { DCHECK_EQ(STAGE_START, stage_); stage_ = STAGE_HIGHLIGHTED; @@ -445,10 +478,10 @@ void ExtensionMessageBubbleFactory::HighlightDevModeExtensions() { if (container_->animating()) MaybeObserve(); else - ShowDevModeBubble(); + ShowHighlightingBubble(); } -void ExtensionMessageBubbleFactory::ShowDevModeBubble() { +void ExtensionMessageBubbleFactory::ShowHighlightingBubble() { DCHECK_EQ(stage_, STAGE_HIGHLIGHTED); stage_ = STAGE_COMPLETE; @@ -458,11 +491,13 @@ void ExtensionMessageBubbleFactory::ShowDevModeBubble() { if (reference_view && reference_view->visible()) anchor_view_ = reference_view; - DevModeBubbleController* weak_controller = controller_.get(); - ExtensionMessageBubbleView* bubble_delegate = new ExtensionMessageBubbleView( - anchor_view_, - views::BubbleBorder::TOP_RIGHT, - scoped_ptr<ExtensionMessageBubbleController>(controller_.release())); + ExtensionMessageBubbleController* weak_controller = controller_.get(); + ExtensionMessageBubbleView* bubble_delegate = + new ExtensionMessageBubbleView( + anchor_view_, + views::BubbleBorder::TOP_RIGHT, + scoped_ptr<ExtensionMessageBubbleController>( + controller_.release())); views::BubbleDelegateView::CreateBubble(bubble_delegate); weak_controller->Show(bubble_delegate); diff --git a/chrome/browser/ui/views/extensions/extension_message_bubble_view.h b/chrome/browser/ui/views/extensions/extension_message_bubble_view.h index c615c18..322139f 100644 --- a/chrome/browser/ui/views/extensions/extension_message_bubble_view.h +++ b/chrome/browser/ui/views/extensions/extension_message_bubble_view.h @@ -60,6 +60,11 @@ class ExtensionMessageBubbleFactory : public BrowserActionsContainerObserver { // Returns true if we show the view (or start the process). bool MaybeShowStartupOverrideExtensionsBubble(views::View* anchor_view); + // Shows the bubble for when there are extensions overriding the proxy (if we + // have not done so already). Returns true if we show the view (or start the + // process of doing so). + bool MaybeShowProxyOverrideExtensionsBubble(views::View* anchor_view); + // Shows the developer mode extensions bubble, if there are extensions running // in developer mode and we have not done so already. // Returns true if we show the view (or start the process). @@ -79,11 +84,17 @@ class ExtensionMessageBubbleFactory : public BrowserActionsContainerObserver { virtual void OnBrowserActionsContainerAnimationEnded() OVERRIDE; virtual void OnBrowserActionsContainerDestroyed() OVERRIDE; + // Sets the stage for highlighting extensions and then showing the bubble + // controlled by |controller|, anchored to |anchor_view|. + void PrepareToHighlightExtensions( + scoped_ptr<ExtensionMessageBubbleController> controller, + views::View* anchor_view); + // Inform the ExtensionToolbarModel to highlight the appropriate extensions. - void HighlightDevModeExtensions(); + void HighlightExtensions(); - // Shows the developer mode bubble, after highlighting the extensions. - void ShowDevModeBubble(); + // Shows the waiting bubbble, after highlighting the extensions. + void ShowHighlightingBubble(); // Finishes the process of showing the developer mode bubble. void Finish(); @@ -101,6 +112,10 @@ class ExtensionMessageBubbleFactory : public BrowserActionsContainerObserver { // the user about the startup pages being overridden. bool shown_startup_override_extensions_bubble_; + // Whether or not we have shown the bubble notifying the user about the proxy + // being overridden. + bool shown_proxy_override_extensions_bubble_; + // Whether or not we have shown the developer mode extensions bubble. bool shown_dev_mode_extensions_bubble_; @@ -119,9 +134,9 @@ class ExtensionMessageBubbleFactory : public BrowserActionsContainerObserver { // is not currently in the process of showing a bubble. views::View* anchor_view_; - // The DevModeBubbleController to use. This will be NULL if the factory is not - // currently in the process of showing a bubble. - scoped_ptr<DevModeBubbleController> controller_; + // The controller to show a bubble for. This will be NULL if the factory is + // not currently in the process of showing a bubble. + scoped_ptr<ExtensionMessageBubbleController> controller_; DISALLOW_COPY_AND_ASSIGN(ExtensionMessageBubbleFactory); }; @@ -172,6 +187,9 @@ class ExtensionMessageBubbleView : public ExtensionMessageBubble, // The controller for this bubble. scoped_ptr<ExtensionMessageBubbleController> controller_; + // The view this bubble is anchored against. + views::View* anchor_view_; + // The headline, labels and buttons on the bubble. views::Label* headline_; views::Link* learn_more_; diff --git a/chrome/browser/ui/views/settings_api_bubble_helper_views.cc b/chrome/browser/ui/views/settings_api_bubble_helper_views.cc index 67199cd..c3dc7f4 100644 --- a/chrome/browser/ui/views/settings_api_bubble_helper_views.cc +++ b/chrome/browser/ui/views/settings_api_bubble_helper_views.cc @@ -19,40 +19,40 @@ #include "content/public/browser/browser_url_handler.h" #include "content/public/browser/navigation_entry.h" +namespace extensions { + namespace { -void ShowSettingsApiBubble(extensions::SettingsApiOverrideType type, +void ShowSettingsApiBubble(SettingsApiOverrideType type, const std::string& extension_id, Profile* profile, views::View* anchor_view, views::BubbleBorder::Arrow arrow) { - scoped_ptr<extensions::SettingsApiBubbleController> settings_api_bubble( - new extensions::SettingsApiBubbleController(profile, type)); + scoped_ptr<SettingsApiBubbleController> settings_api_bubble( + new SettingsApiBubbleController(profile, type)); if (!settings_api_bubble->ShouldShow(extension_id)) return; - extensions::SettingsApiBubbleController* controller = - settings_api_bubble.get(); - extensions::ExtensionMessageBubbleView* bubble_delegate = - new extensions::ExtensionMessageBubbleView( + SettingsApiBubbleController* controller = settings_api_bubble.get(); + ExtensionMessageBubbleView* bubble_delegate = + new ExtensionMessageBubbleView( anchor_view, arrow, settings_api_bubble.PassAs< - extensions::ExtensionMessageBubbleController>()); + ExtensionMessageBubbleController>()); views::BubbleDelegateView::CreateBubble(bubble_delegate); controller->Show(bubble_delegate); } } // namespace -namespace extensions { - void MaybeShowExtensionControlledHomeNotification(Browser* browser) { #if !defined(OS_WIN) return; #endif - const Extension* extension = OverridesHomepage(browser->profile(), NULL); + const Extension* extension = + GetExtensionOverridingHomepage(browser->profile(), NULL); if (extension) { // The bubble will try to anchor itself against the home button views::View* anchor_view = BrowserView::GetBrowserViewForBrowser(browser)-> @@ -76,7 +76,7 @@ void MaybeShowExtensionControlledSearchNotification( if (AutocompleteMatch::IsSearchType(match.type) && match.type != AutocompleteMatchType::SEARCH_OTHER_ENGINE) { const Extension* extension = - OverridesSearchEngine(profile, NULL); + GetExtensionOverridingSearchEngine(profile, NULL); if (extension) { ToolbarView* toolbar = BrowserView::GetBrowserViewForBrowser( diff --git a/chrome/browser/ui/views/toolbar/browser_action_view.cc b/chrome/browser/ui/views/toolbar/browser_action_view.cc index 6507988..6c13116 100644 --- a/chrome/browser/ui/views/toolbar/browser_action_view.cc +++ b/chrome/browser/ui/views/toolbar/browser_action_view.cc @@ -15,6 +15,7 @@ #include "chrome/browser/themes/theme_service.h" #include "chrome/browser/themes/theme_service_factory.h" #include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/view_ids.h" #include "chrome/browser/ui/views/toolbar/browser_actions_container.h" #include "chrome/browser/ui/views/toolbar/toolbar_view.h" #include "extensions/common/extension.h" @@ -51,6 +52,7 @@ BrowserActionView::BrowserActionView(const Extension* extension, delegate_(delegate), button_(NULL), extension_(extension) { + set_id(VIEW_ID_BROWSER_ACTION); button_ = new BrowserActionButton(extension_, browser_, delegate_); button_->set_drag_controller(delegate_); button_->set_owned_by_client(); diff --git a/chrome/browser/ui/webui/options/browser_options_handler.cc b/chrome/browser/ui/webui/options/browser_options_handler.cc index a12487e..0446457 100644 --- a/chrome/browser/ui/webui/options/browser_options_handler.cc +++ b/chrome/browser/ui/webui/options/browser_options_handler.cc @@ -309,6 +309,7 @@ void BrowserOptionsHandler::GetLocalizedValues(base::DictionaryValue* values) { { "sectionTitleAppearance", IDS_APPEARANCE_GROUP_NAME }, { "sectionTitleDefaultBrowser", IDS_OPTIONS_DEFAULTBROWSER_GROUP_NAME }, { "sectionTitleUsers", IDS_PROFILES_OPTIONS_GROUP_NAME }, + { "sectionTitleProxy", IDS_OPTIONS_PROXY_GROUP_NAME }, { "sectionTitleSearch", IDS_OPTIONS_DEFAULTSEARCH_GROUP_NAME }, { "sectionTitleStartup", IDS_OPTIONS_STARTUP_GROUP_NAME }, { "sectionTitleSync", IDS_SYNC_OPTIONS_GROUP_NAME }, @@ -1707,9 +1708,13 @@ void BrowserOptionsHandler::SetupProxySettingsSection() { base::FundamentalValue disabled(is_win_ash || (proxy_config && !proxy_config->IsUserModifiable())); base::FundamentalValue extension_controlled(is_extension_controlled); - web_ui()->CallJavascriptFunction("BrowserOptions.setupProxySettingsSection", + web_ui()->CallJavascriptFunction("BrowserOptions.setupProxySettingsButton", disabled, extension_controlled); +#if defined(OS_WIN) + SetupExtensionControlledIndicators(); +#endif // defined(OS_WIN) + #endif // !defined(OS_CHROMEOS) } @@ -1749,16 +1754,18 @@ void BrowserOptionsHandler::SetupExtensionControlledIndicators() { base::DictionaryValue extension_controlled; // Check if an extension is overriding the Search Engine. - const extensions::Extension* extension = extensions::OverridesSearchEngine( - Profile::FromWebUI(web_ui()), NULL); + const extensions::Extension* extension = + extensions::GetExtensionOverridingSearchEngine( + Profile::FromWebUI(web_ui()), NULL); AppendExtensionData("searchEngine", extension, &extension_controlled); // Check if an extension is overriding the Home page. - extension = extensions::OverridesHomepage(Profile::FromWebUI(web_ui()), NULL); + extension = extensions::GetExtensionOverridingHomepage( + Profile::FromWebUI(web_ui()), NULL); AppendExtensionData("homePage", extension, &extension_controlled); // Check if an extension is overriding the Startup pages. - extension = extensions::OverridesStartupPages( + extension = extensions::GetExtensionOverridingStartupPages( Profile::FromWebUI(web_ui()), NULL); AppendExtensionData("startUpPage", extension, &extension_controlled); @@ -1779,6 +1786,11 @@ void BrowserOptionsHandler::SetupExtensionControlledIndicators() { } AppendExtensionData("newTabPage", extension, &extension_controlled); + // Check if an extension is overwriting the proxy setting. + extension = extensions::GetExtensionOverridingProxy( + Profile::FromWebUI(web_ui())); + AppendExtensionData("proxy", extension, &extension_controlled); + web_ui()->CallJavascriptFunction("BrowserOptions.toggleExtensionIndicators", extension_controlled); #endif // defined(OS_WIN) diff --git a/chrome/chrome_browser_extensions.gypi b/chrome/chrome_browser_extensions.gypi index 7088dc5..d58c43e 100644 --- a/chrome/chrome_browser_extensions.gypi +++ b/chrome/chrome_browser_extensions.gypi @@ -868,6 +868,8 @@ 'browser/extensions/permissions_updater.h', 'browser/extensions/plugin_manager.cc', 'browser/extensions/plugin_manager.h', + 'browser/extensions/proxy_overridden_bubble_controller.cc', + 'browser/extensions/proxy_overridden_bubble_controller.h', 'browser/extensions/requirements_checker.cc', 'browser/extensions/requirements_checker.h', 'browser/extensions/sandboxed_unpacker.cc', diff --git a/extensions/browser/extension_prefs.cc b/extensions/browser/extension_prefs.cc index fdba64a..d8a2d8a 100644 --- a/extensions/browser/extension_prefs.cc +++ b/extensions/browser/extension_prefs.cc @@ -78,6 +78,7 @@ const char kPrefBlacklistAcknowledged[] = "ack_blacklist"; const char kPrefWipeoutAcknowledged[] = "ack_wiped"; const char kPrefSettingsBubbleAcknowledged[] = "ack_settings_bubble"; const char kPrefNtpBubbleAcknowledged[] = "ack_ntp_bubble"; +const char kPrefProxyBubbleAcknowledged[] = "ack_proxy_bubble"; // Indicates whether the external extension was installed during the first // run of this profile. @@ -755,6 +756,19 @@ void ExtensionPrefs::SetNtpOverriddenBubbleBeenAcknowledged( value ? base::Value::CreateBooleanValue(value) : NULL); } +bool ExtensionPrefs::HasProxyOverriddenBubbleBeenAcknowledged( + const std::string& extension_id) { + return ReadPrefAsBooleanAndReturn(extension_id, kPrefProxyBubbleAcknowledged); +} + +void ExtensionPrefs::SetProxyOverriddenBubbleBeenAcknowledged( + const std::string& extension_id, + bool value) { + UpdateExtensionPref(extension_id, + kPrefProxyBubbleAcknowledged, + value ? base::Value::CreateBooleanValue(value) : NULL); +} + bool ExtensionPrefs::SetAlertSystemFirstRun() { if (prefs_->GetBoolean(pref_names::kAlertsInitialized)) { return true; diff --git a/extensions/browser/extension_prefs.h b/extensions/browser/extension_prefs.h index 069b604..50bb03b 100644 --- a/extensions/browser/extension_prefs.h +++ b/extensions/browser/extension_prefs.h @@ -329,6 +329,13 @@ class ExtensionPrefs : public ExtensionScopedPrefs, public KeyedService { void SetNtpOverriddenBubbleBeenAcknowledged(const std::string& extension_id, bool value); + // Whether the user has been notified about extension with |extension_id| + // overriding the proxy. + bool HasProxyOverriddenBubbleBeenAcknowledged( + const std::string& extension_id); + void SetProxyOverriddenBubbleBeenAcknowledged(const std::string& extension_id, + bool value); + // Returns true if the extension notification code has already run for the // first time for this profile. Currently we use this flag to mean that any // extensions that would trigger notifications should get silently |