| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "base/command_line.h" |
| #include "base/macros.h" |
| #include "base/threading/thread_restrictions.h" |
| #include "build/build_config.h" |
| #include "chrome/app/chrome_command_ids.h" |
| #include "chrome/browser/extensions/active_tab_permission_granter.h" |
| #include "chrome/browser/extensions/api/commands/command_service.h" |
| #include "chrome/browser/extensions/browser_action_test_util.h" |
| #include "chrome/browser/extensions/component_loader.h" |
| #include "chrome/browser/extensions/extension_action.h" |
| #include "chrome/browser/extensions/extension_action_manager.h" |
| #include "chrome/browser/extensions/extension_apitest.h" |
| #include "chrome/browser/extensions/extension_service.h" |
| #include "chrome/browser/sessions/session_tab_helper.h" |
| #include "chrome/browser/ui/browser.h" |
| #include "chrome/browser/ui/browser_command_controller.h" |
| #include "chrome/browser/ui/browser_commands.h" |
| #include "chrome/browser/ui/tabs/tab_strip_model.h" |
| #include "chrome/test/base/interactive_test_utils.h" |
| #include "chrome/test/base/ui_test_utils.h" |
| #include "content/public/browser/notification_service.h" |
| #include "content/public/browser/web_contents.h" |
| #include "content/public/test/javascript_test_observer.h" |
| #include "extensions/browser/extension_registry.h" |
| #include "extensions/common/extension.h" |
| #include "extensions/common/feature_switch.h" |
| #include "extensions/common/manifest_constants.h" |
| #include "extensions/common/permissions/permissions_data.h" |
| #include "extensions/test/extension_test_message_listener.h" |
| #include "extensions/test/result_catcher.h" |
| #include "net/test/embedded_test_server/embedded_test_server.h" |
| |
| using content::WebContents; |
| |
| namespace extensions { |
| |
| namespace { |
| |
| // This extension ID is used for tests require a stable ID over multiple |
| // extension installs. |
| const char kId[] = "pgoakhfeplldmjheffidklpoklkppipp"; |
| |
| // Default keybinding to use for emulating user-defined shortcut overrides. The |
| // test extensions use Alt+Shift+F and Alt+Shift+H. |
| const char kAltShiftG[] = "Alt+Shift+G"; |
| |
| // Name of the command for the "basics" test extension. |
| const char kBasicsShortcutCommandName[] = "toggle-feature"; |
| // Name of the command for the overwrite_bookmark_shortcut test extension. |
| const char kOverwriteBookmarkShortcutCommandName[] = "send message"; |
| |
| #if defined(OS_MACOSX) |
| const char kBookmarkKeybinding[] = "Command+D"; |
| #else |
| const char kBookmarkKeybinding[] = "Ctrl+D"; |
| #endif // defined(OS_MACOSX) |
| |
| bool SendBookmarkKeyPressSync(Browser* browser) { |
| return ui_test_utils::SendKeyPressSync( |
| browser, ui::VKEY_D, |
| #if defined(OS_MACOSX) |
| false, false, false, true |
| #else |
| true, false, false, false |
| #endif |
| ); |
| } |
| |
| // Named command for media key overwrite test. |
| const char kMediaKeyTestCommand[] = "test_mediakeys_update"; |
| |
| // A scoped observer that listens for dom automation messages. |
| class DomMessageListener : public content::TestMessageHandler { |
| public: |
| explicit DomMessageListener(content::WebContents* web_contents); |
| ~DomMessageListener() override; |
| |
| // Wait until a message is received. |
| void Wait(); |
| |
| // Clears and resets the observer. |
| void Clear(); |
| |
| const std::string& message() const { return message_; } |
| |
| private: |
| // content::TestMessageHandler: |
| MessageResponse HandleMessage(const std::string& json) override; |
| void Reset() override; |
| |
| // The message received. Note that this will be JSON, so if it is a string, |
| // it will be wrapped in quotes. |
| std::string message_; |
| |
| content::JavascriptTestObserver observer_; |
| |
| DISALLOW_COPY_AND_ASSIGN(DomMessageListener); |
| }; |
| |
| DomMessageListener::DomMessageListener(content::WebContents* web_contents) |
| : observer_(web_contents, this) { |
| } |
| |
| DomMessageListener::~DomMessageListener() { |
| } |
| |
| void DomMessageListener::Wait() { |
| observer_.Run(); |
| } |
| |
| void DomMessageListener::Clear() { |
| // We don't just call this in DomMessageListener::Reset() because the |
| // JavascriptTestObserver's Reset() method also resets its handler (this). |
| observer_.Reset(); |
| } |
| |
| content::TestMessageHandler::MessageResponse DomMessageListener::HandleMessage( |
| const std::string& json) { |
| message_ = json; |
| return DONE; |
| } |
| |
| void DomMessageListener::Reset() { |
| TestMessageHandler::Reset(); |
| message_.clear(); |
| } |
| |
| } // namespace |
| |
| class CommandsApiTest : public ExtensionApiTest { |
| public: |
| CommandsApiTest() {} |
| ~CommandsApiTest() override {} |
| |
| protected: |
| bool IsGrantedForTab(const Extension* extension, |
| const content::WebContents* web_contents) { |
| return extension->permissions_data()->HasAPIPermissionForTab( |
| SessionTabHelper::IdForTab(web_contents), APIPermission::kTab); |
| } |
| |
| #if defined(OS_CHROMEOS) |
| void RunChromeOSConversionTest(const std::string& extension_path) { |
| // Setup the environment. |
| ASSERT_TRUE(embedded_test_server()->Start()); |
| ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser())); |
| ASSERT_TRUE(RunExtensionTest(extension_path)) << message_; |
| ui_test_utils::NavigateToURL( |
| browser(), embedded_test_server()->GetURL("/extensions/test_file.txt")); |
| |
| ResultCatcher catcher; |
| |
| // Send all expected keys (Search+Shift+{Left, Up, Right, Down}). |
| ASSERT_TRUE(ui_test_utils::SendKeyPressSync( |
| browser(), ui::VKEY_LEFT, false, true, false, true)); |
| ASSERT_TRUE(ui_test_utils::SendKeyPressSync( |
| browser(), ui::VKEY_UP, false, true, false, true)); |
| ASSERT_TRUE(ui_test_utils::SendKeyPressSync( |
| browser(), ui::VKEY_RIGHT, false, true, false, true)); |
| ASSERT_TRUE(ui_test_utils::SendKeyPressSync( |
| browser(), ui::VKEY_DOWN, false, true, false, true)); |
| |
| ASSERT_TRUE(catcher.GetNextResult()); |
| } |
| #endif // OS_CHROMEOS |
| }; |
| |
| // Test the basic functionality of the Keybinding API: |
| // - That pressing the shortcut keys should perform actions (activate the |
| // browser action or send an event). |
| // - Note: Page action keybindings are tested in PageAction test below. |
| // - The shortcut keys taken by one extension are not overwritten by the last |
| // installed extension. |
| IN_PROC_BROWSER_TEST_F(CommandsApiTest, Basic) { |
| ASSERT_TRUE(embedded_test_server()->Start()); |
| ASSERT_TRUE(RunExtensionTest("keybinding/basics")) << message_; |
| const Extension* extension = GetSingleLoadedExtension(); |
| ASSERT_TRUE(extension) << message_; |
| |
| // Load this extension, which uses the same keybindings but sets the page |
| // to different colors. This is so we can see that it doesn't interfere. We |
| // don't test this extension in any other way (it should otherwise be |
| // immaterial to this test). |
| ASSERT_TRUE(RunExtensionTest("keybinding/conflicting")) << message_; |
| |
| BrowserActionTestUtil browser_actions_bar(browser()); |
| // Test that there are two browser actions in the toolbar. |
| ASSERT_EQ(2, browser_actions_bar.NumberOfBrowserActions()); |
| |
| ui_test_utils::NavigateToURL( |
| browser(), embedded_test_server()->GetURL("/extensions/test_file.txt")); |
| |
| // activeTab shouldn't have been granted yet. |
| WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents(); |
| ASSERT_TRUE(tab); |
| |
| EXPECT_FALSE(IsGrantedForTab(extension, tab)); |
| |
| ExtensionTestMessageListener test_listener(false); // Won't reply. |
| // Activate the browser action shortcut (Ctrl+Shift+F). |
| ASSERT_TRUE(ui_test_utils::SendKeyPressSync( |
| browser(), ui::VKEY_F, true, true, false, false)); |
| EXPECT_TRUE(test_listener.WaitUntilSatisfied()); |
| // activeTab should now be granted. |
| EXPECT_TRUE(IsGrantedForTab(extension, tab)); |
| // Verify the command worked. |
| EXPECT_EQ(std::string("basics browser action"), test_listener.message()); |
| |
| test_listener.Reset(); |
| // Activate the command shortcut (Ctrl+Shift+Y). |
| ASSERT_TRUE(ui_test_utils::SendKeyPressSync( |
| browser(), ui::VKEY_Y, true, true, false, false)); |
| EXPECT_TRUE(test_listener.WaitUntilSatisfied()); |
| EXPECT_EQ(std::string(kBasicsShortcutCommandName), test_listener.message()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(CommandsApiTest, PageAction) { |
| ASSERT_TRUE(embedded_test_server()->Start()); |
| ASSERT_TRUE(RunExtensionTest("keybinding/page_action")) << message_; |
| const Extension* extension = GetSingleLoadedExtension(); |
| ASSERT_TRUE(extension) << message_; |
| |
| { |
| // Load a page, the extension will detect the navigation and request to show |
| // the page action icon. |
| ResultCatcher catcher; |
| ui_test_utils::NavigateToURL( |
| browser(), embedded_test_server()->GetURL("/extensions/test_file.txt")); |
| ASSERT_TRUE(catcher.GetNextResult()); |
| } |
| |
| // Make sure it appears and is the right one. |
| ASSERT_TRUE(WaitForPageActionVisibilityChangeTo(1)); |
| int tab_id = SessionTabHelper::FromWebContents( |
| browser()->tab_strip_model()->GetActiveWebContents())->session_id().id(); |
| ExtensionAction* action = |
| ExtensionActionManager::Get(browser()->profile())-> |
| GetPageAction(*extension); |
| ASSERT_TRUE(action); |
| EXPECT_EQ("Send message", action->GetTitle(tab_id)); |
| |
| ExtensionTestMessageListener test_listener(false); // Won't reply. |
| test_listener.set_extension_id(extension->id()); |
| |
| // Activate the shortcut (Alt+Shift+F). |
| ASSERT_TRUE(ui_test_utils::SendKeyPressSync( |
| browser(), ui::VKEY_F, false, true, true, false)); |
| |
| test_listener.WaitUntilSatisfied(); |
| EXPECT_EQ("clicked", test_listener.message()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(CommandsApiTest, PageActionKeyUpdated) { |
| ASSERT_TRUE(embedded_test_server()->Start()); |
| ASSERT_TRUE(RunExtensionTest("keybinding/page_action")) << message_; |
| const Extension* extension = GetSingleLoadedExtension(); |
| ASSERT_TRUE(extension) << message_; |
| |
| CommandService* command_service = CommandService::Get(browser()->profile()); |
| // Simulate the user setting the keybinding to Alt+Shift+G. |
| command_service->UpdateKeybindingPrefs( |
| extension->id(), manifest_values::kPageActionCommandEvent, kAltShiftG); |
| |
| { |
| // Load a page. The extension will detect the navigation and request to show |
| // the page action icon. |
| ResultCatcher catcher; |
| ui_test_utils::NavigateToURL( |
| browser(), embedded_test_server()->GetURL("/extensions/test_file.txt")); |
| ASSERT_TRUE(catcher.GetNextResult()); |
| } |
| |
| ExtensionTestMessageListener test_listener(false); // Won't reply. |
| test_listener.set_extension_id(extension->id()); |
| |
| // Activate the shortcut. |
| ASSERT_TRUE(ui_test_utils::SendKeyPressSync( |
| browser(), ui::VKEY_G, false, true, true, false)); |
| |
| test_listener.WaitUntilSatisfied(); |
| EXPECT_EQ("clicked", test_listener.message()); |
| } |
| |
| // This test validates that the getAll query API function returns registered |
| // commands as well as synthesized ones and that inactive commands (like the |
| // synthesized ones are in nature) have no shortcuts. |
| IN_PROC_BROWSER_TEST_F(CommandsApiTest, SynthesizedCommand) { |
| ASSERT_TRUE(embedded_test_server()->Start()); |
| ASSERT_TRUE(RunExtensionTest("keybinding/synthesized")) << message_; |
| } |
| |
| // This test validates that an extension cannot request a shortcut that is |
| // already in use by Chrome. |
| IN_PROC_BROWSER_TEST_F(CommandsApiTest, DontOverwriteSystemShortcuts) { |
| ASSERT_TRUE(embedded_test_server()->Start()); |
| |
| ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser())); |
| |
| ASSERT_TRUE(RunExtensionTest("keybinding/dont_overwrite_system")) << message_; |
| |
| ui_test_utils::NavigateToURL( |
| browser(), embedded_test_server()->GetURL("/extensions/test_file.txt")); |
| |
| // Activate the regular shortcut (Alt+Shift+F). |
| ExtensionTestMessageListener alt_shift_f_listener("alt_shift_f", false); |
| ASSERT_TRUE(ui_test_utils::SendKeyPressSync( |
| browser(), ui::VKEY_F, false, true, true, false)); |
| EXPECT_TRUE(alt_shift_f_listener.WaitUntilSatisfied()); |
| |
| // Try to activate the bookmark shortcut (Ctrl+D). This should not work |
| // without requesting via chrome_settings_overrides. |
| // |
| // Since keypresses are sent synchronously, we can check this by first sending |
| // Ctrl+D (which shouldn't work), followed by Alt+Shift+F (which should work), |
| // and listening for both. If, by the time we receive the Alt+Shift+F |
| // response, we haven't received a response for Ctrl+D, it is safe to say we |
| // won't receive one. |
| { |
| ExtensionTestMessageListener ctrl_d_listener("ctrl_d", false); |
| alt_shift_f_listener.Reset(); |
| // Send Ctrl+D. |
| ASSERT_TRUE(SendBookmarkKeyPressSync(browser())); |
| // Send Alt+Shift+F. |
| ASSERT_TRUE(ui_test_utils::SendKeyPressSync( |
| browser(), ui::VKEY_F, false, true, true, false)); |
| EXPECT_TRUE(alt_shift_f_listener.WaitUntilSatisfied()); |
| EXPECT_FALSE(ctrl_d_listener.was_satisfied()); |
| } |
| |
| // Try to activate the Ctrl+F shortcut (shouldn't work). |
| { |
| ExtensionTestMessageListener ctrl_f_listener("ctrl_f", false); |
| alt_shift_f_listener.Reset(); |
| // Send Ctrl+F. |
| ASSERT_TRUE(ui_test_utils::SendKeyPressSync( |
| browser(), ui::VKEY_F, true, false, false, false)); |
| // Send Alt+Shift+F. |
| ASSERT_TRUE(ui_test_utils::SendKeyPressSync( |
| browser(), ui::VKEY_F, false, true, true, false)); |
| EXPECT_TRUE(alt_shift_f_listener.WaitUntilSatisfied()); |
| EXPECT_FALSE(ctrl_f_listener.was_satisfied()); |
| } |
| } |
| |
| // This test validates that an extension can remove the Chrome bookmark shortcut |
| // if it has requested to do so. |
| IN_PROC_BROWSER_TEST_F(CommandsApiTest, RemoveBookmarkShortcut) { |
| ASSERT_TRUE(embedded_test_server()->Start()); |
| |
| ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser())); |
| |
| // This functionality requires a feature flag. |
| base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( |
| "--enable-override-bookmarks-ui", "1"); |
| |
| ASSERT_TRUE(RunExtensionTest("keybinding/remove_bookmark_shortcut")) |
| << message_; |
| |
| EXPECT_FALSE(chrome::IsCommandEnabled(browser(), IDC_BOOKMARK_PAGE)); |
| } |
| |
| // This test validates that an extension cannot remove the Chrome bookmark |
| // shortcut without being given permission with a feature flag. |
| IN_PROC_BROWSER_TEST_F(CommandsApiTest, |
| RemoveBookmarkShortcutWithoutPermission) { |
| ASSERT_TRUE(embedded_test_server()->Start()); |
| |
| ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser())); |
| |
| EXPECT_TRUE(RunExtensionTestIgnoreManifestWarnings( |
| "keybinding/remove_bookmark_shortcut")); |
| |
| EXPECT_TRUE(chrome::IsCommandEnabled(browser(), IDC_BOOKMARK_PAGE)); |
| } |
| |
| // This test validates that an extension that removes the Chrome bookmark |
| // shortcut continues to remove the bookmark shortcut with a user-assigned |
| // Ctrl+D shortcut (i.e. it does not trigger the overwrite functionality). |
| IN_PROC_BROWSER_TEST_F(CommandsApiTest, |
| RemoveBookmarkShortcutWithUserKeyBinding) { |
| ASSERT_TRUE(embedded_test_server()->Start()); |
| |
| ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser())); |
| |
| // This functionality requires a feature flag. |
| base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( |
| "--enable-override-bookmarks-ui", "1"); |
| |
| ASSERT_TRUE(RunExtensionTest("keybinding/remove_bookmark_shortcut")) |
| << message_; |
| |
| // Check that the shortcut is removed. |
| CommandService* command_service = CommandService::Get(browser()->profile()); |
| const Extension* extension = GetSingleLoadedExtension(); |
| // Simulate the user setting a keybinding to Ctrl+D. |
| command_service->UpdateKeybindingPrefs( |
| extension->id(), manifest_values::kBrowserActionCommandEvent, |
| kBookmarkKeybinding); |
| |
| // Force the command enable state to be recalculated. |
| browser()->command_controller()->ExtensionStateChanged(); |
| |
| EXPECT_FALSE(chrome::IsCommandEnabled(browser(), IDC_BOOKMARK_PAGE)); |
| } |
| |
| // This test validates that an extension can override the Chrome bookmark |
| // shortcut if it has requested to do so. |
| IN_PROC_BROWSER_TEST_F(CommandsApiTest, OverwriteBookmarkShortcut) { |
| ASSERT_TRUE(embedded_test_server()->Start()); |
| |
| ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser())); |
| |
| // This functionality requires a feature flag. |
| base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( |
| "--enable-override-bookmarks-ui", "1"); |
| |
| ASSERT_TRUE(RunExtensionTest("keybinding/overwrite_bookmark_shortcut")) |
| << message_; |
| |
| ui_test_utils::NavigateToURL( |
| browser(), embedded_test_server()->GetURL("/extensions/test_file.txt")); |
| |
| // Activate the shortcut (Ctrl+D) to send a test message. |
| ExtensionTestMessageListener test_listener(false); // Won't reply. |
| ASSERT_TRUE(SendBookmarkKeyPressSync(browser())); |
| EXPECT_TRUE(test_listener.WaitUntilSatisfied()); |
| EXPECT_EQ(std::string(kOverwriteBookmarkShortcutCommandName), |
| test_listener.message()); |
| } |
| |
| // This test validates that an extension that requests to override the Chrome |
| // bookmark shortcut, but does not get the keybinding, does not remove the |
| // bookmark UI. |
| IN_PROC_BROWSER_TEST_F(CommandsApiTest, |
| OverwriteBookmarkShortcutWithoutKeybinding) { |
| // This functionality requires a feature flag. |
| base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( |
| "--enable-override-bookmarks-ui", "1"); |
| |
| ASSERT_TRUE(embedded_test_server()->Start()); |
| |
| EXPECT_TRUE(chrome::IsCommandEnabled(browser(), IDC_BOOKMARK_PAGE)); |
| |
| ASSERT_TRUE(RunExtensionTest("keybinding/overwrite_bookmark_shortcut")) |
| << message_; |
| |
| const Extension* extension = GetSingleLoadedExtension(); |
| CommandService* command_service = CommandService::Get(browser()->profile()); |
| CommandMap commands; |
| // Verify the expected command is present. |
| EXPECT_TRUE(command_service->GetNamedCommands( |
| extension->id(), CommandService::SUGGESTED, CommandService::ANY_SCOPE, |
| &commands)); |
| EXPECT_EQ(1u, commands.count(kOverwriteBookmarkShortcutCommandName)); |
| |
| // Simulate the user removing the Ctrl+D keybinding from the command. |
| command_service->RemoveKeybindingPrefs( |
| extension->id(), kOverwriteBookmarkShortcutCommandName); |
| |
| // Force the command enable state to be recalculated. |
| browser()->command_controller()->ExtensionStateChanged(); |
| |
| EXPECT_TRUE(chrome::IsCommandEnabled(browser(), IDC_BOOKMARK_PAGE)); |
| } |
| |
| // This test validates that an extension override of the Chrome bookmark |
| // shortcut does not supersede the same keybinding by web pages. |
| IN_PROC_BROWSER_TEST_F(CommandsApiTest, |
| OverwriteBookmarkShortcutDoesNotOverrideWebKeybinding) { |
| ASSERT_TRUE(embedded_test_server()->Start()); |
| |
| ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser())); |
| |
| // This functionality requires a feature flag. |
| base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( |
| "--enable-override-bookmarks-ui", "1"); |
| |
| ASSERT_TRUE(RunExtensionTest("keybinding/overwrite_bookmark_shortcut")) |
| << message_; |
| |
| ui_test_utils::NavigateToURL( |
| browser(), embedded_test_server()->GetURL( |
| "/extensions/test_file_with_ctrl-d_keybinding.html")); |
| |
| WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents(); |
| ASSERT_TRUE(tab); |
| |
| // Activate the shortcut (Ctrl+D) which should be handled by the page and send |
| // a test message. |
| DomMessageListener listener(tab); |
| ASSERT_TRUE(SendBookmarkKeyPressSync(browser())); |
| listener.Wait(); |
| EXPECT_EQ(std::string("\"web page received\""), listener.message()); |
| } |
| |
| // This test validates that user-set override of the Chrome bookmark shortcut in |
| // an extension that does not request it does supersede the same keybinding by |
| // web pages. |
| IN_PROC_BROWSER_TEST_F(CommandsApiTest, |
| OverwriteBookmarkShortcutByUserOverridesWebKeybinding) { |
| ASSERT_TRUE(embedded_test_server()->Start()); |
| |
| ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser())); |
| |
| // This functionality requires a feature flag. |
| base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( |
| "--enable-override-bookmarks-ui", "1"); |
| |
| ASSERT_TRUE(RunExtensionTest("keybinding/basics")) |
| << message_; |
| |
| CommandService* command_service = CommandService::Get(browser()->profile()); |
| |
| const Extension* extension = GetSingleLoadedExtension(); |
| // Simulate the user setting the keybinding to Ctrl+D. |
| command_service->UpdateKeybindingPrefs( |
| extension->id(), manifest_values::kBrowserActionCommandEvent, |
| kBookmarkKeybinding); |
| |
| ui_test_utils::NavigateToURL( |
| browser(), embedded_test_server()->GetURL( |
| "/extensions/test_file_with_ctrl-d_keybinding.html")); |
| |
| ExtensionTestMessageListener test_listener(false); // Won't reply. |
| // Activate the shortcut (Ctrl+D) which should be handled by the extension. |
| ASSERT_TRUE(SendBookmarkKeyPressSync(browser())); |
| EXPECT_TRUE(test_listener.WaitUntilSatisfied()); |
| EXPECT_EQ(std::string("basics browser action"), test_listener.message()); |
| } |
| |
| #if defined(OS_WIN) |
| // Currently this feature is implemented on Windows only. |
| #define MAYBE_AllowDuplicatedMediaKeys AllowDuplicatedMediaKeys |
| #else |
| #define MAYBE_AllowDuplicatedMediaKeys DISABLED_AllowDuplicatedMediaKeys |
| #endif |
| |
| // Test that media keys go to all extensions that register for them. |
| IN_PROC_BROWSER_TEST_F(CommandsApiTest, MAYBE_AllowDuplicatedMediaKeys) { |
| ResultCatcher catcher; |
| ASSERT_TRUE(RunExtensionTest("keybinding/non_global_media_keys_0")) |
| << message_; |
| ASSERT_TRUE(catcher.GetNextResult()); |
| ASSERT_TRUE(RunExtensionTest("keybinding/non_global_media_keys_1")) |
| << message_; |
| ASSERT_TRUE(catcher.GetNextResult()); |
| |
| // Activate the Media Stop key. |
| ASSERT_TRUE(ui_test_utils::SendKeyPressSync( |
| browser(), ui::VKEY_MEDIA_STOP, false, false, false, false)); |
| |
| // We should get two success result. |
| ASSERT_TRUE(catcher.GetNextResult()); |
| ASSERT_TRUE(catcher.GetNextResult()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(CommandsApiTest, ShortcutAddedOnUpdate) { |
| base::ThreadRestrictions::ScopedAllowIO allow_io; |
| base::ScopedTempDir scoped_temp_dir; |
| EXPECT_TRUE(scoped_temp_dir.CreateUniqueTempDir()); |
| base::FilePath pem_path = test_data_dir_. |
| AppendASCII("keybinding").AppendASCII("keybinding.pem"); |
| base::FilePath path_v1_unassigned = PackExtensionWithOptions( |
| test_data_dir_.AppendASCII("keybinding") |
| .AppendASCII("update") |
| .AppendASCII("v1_unassigned"), |
| scoped_temp_dir.GetPath().AppendASCII("v1_unassigned.crx"), pem_path, |
| base::FilePath()); |
| base::FilePath path_v2 = |
| PackExtensionWithOptions(test_data_dir_.AppendASCII("keybinding") |
| .AppendASCII("update") |
| .AppendASCII("v2"), |
| scoped_temp_dir.GetPath().AppendASCII("v2.crx"), |
| pem_path, base::FilePath()); |
| |
| ExtensionRegistry* registry = ExtensionRegistry::Get(browser()->profile()); |
| CommandService* command_service = CommandService::Get(browser()->profile()); |
| |
| // Install v1 of the extension without keybinding assigned. |
| ASSERT_TRUE(InstallExtension(path_v1_unassigned, 1)); |
| EXPECT_TRUE(registry->GetExtensionById(kId, ExtensionRegistry::ENABLED) != |
| NULL); |
| |
| // Verify it is set to nothing. |
| ui::Accelerator accelerator = command_service->FindCommandByName( |
| kId, manifest_values::kBrowserActionCommandEvent).accelerator(); |
| EXPECT_EQ(ui::VKEY_UNKNOWN, accelerator.key_code()); |
| |
| // Update to version 2 with keybinding. |
| EXPECT_TRUE(UpdateExtension(kId, path_v2, 0)); |
| EXPECT_TRUE(registry->GetExtensionById(kId, ExtensionRegistry::ENABLED) != |
| NULL); |
| |
| // Verify it has a command of Alt+Shift+F. |
| accelerator = command_service->FindCommandByName( |
| kId, manifest_values::kBrowserActionCommandEvent).accelerator(); |
| EXPECT_EQ(ui::VKEY_F, accelerator.key_code()); |
| EXPECT_FALSE(accelerator.IsCtrlDown()); |
| EXPECT_TRUE(accelerator.IsShiftDown()); |
| EXPECT_TRUE(accelerator.IsAltDown()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(CommandsApiTest, ShortcutChangedOnUpdate) { |
| base::ThreadRestrictions::ScopedAllowIO allow_io; |
| base::ScopedTempDir scoped_temp_dir; |
| EXPECT_TRUE(scoped_temp_dir.CreateUniqueTempDir()); |
| base::FilePath pem_path = test_data_dir_. |
| AppendASCII("keybinding").AppendASCII("keybinding.pem"); |
| base::FilePath path_v1 = |
| PackExtensionWithOptions(test_data_dir_.AppendASCII("keybinding") |
| .AppendASCII("update") |
| .AppendASCII("v1"), |
| scoped_temp_dir.GetPath().AppendASCII("v1.crx"), |
| pem_path, base::FilePath()); |
| base::FilePath path_v2_reassigned = PackExtensionWithOptions( |
| test_data_dir_.AppendASCII("keybinding") |
| .AppendASCII("update") |
| .AppendASCII("v2_reassigned"), |
| scoped_temp_dir.GetPath().AppendASCII("v2_reassigned.crx"), pem_path, |
| base::FilePath()); |
| |
| ExtensionRegistry* registry = ExtensionRegistry::Get(browser()->profile()); |
| CommandService* command_service = CommandService::Get(browser()->profile()); |
| |
| // Install v1 of the extension. |
| ASSERT_TRUE(InstallExtension(path_v1, 1)); |
| EXPECT_TRUE(registry->GetExtensionById(kId, ExtensionRegistry::ENABLED) != |
| NULL); |
| |
| // Verify it has a command of Alt+Shift+F. |
| ui::Accelerator accelerator = command_service->FindCommandByName( |
| kId, manifest_values::kBrowserActionCommandEvent).accelerator(); |
| EXPECT_EQ(ui::VKEY_F, accelerator.key_code()); |
| EXPECT_FALSE(accelerator.IsCtrlDown()); |
| EXPECT_TRUE(accelerator.IsShiftDown()); |
| EXPECT_TRUE(accelerator.IsAltDown()); |
| |
| // Update to version 2 with different keybinding assigned. |
| EXPECT_TRUE(UpdateExtension(kId, path_v2_reassigned, 0)); |
| EXPECT_TRUE(registry->GetExtensionById(kId, ExtensionRegistry::ENABLED) != |
| NULL); |
| |
| // Verify it has a command of Alt+Shift+H. |
| accelerator = command_service->FindCommandByName( |
| kId, manifest_values::kBrowserActionCommandEvent).accelerator(); |
| EXPECT_EQ(ui::VKEY_H, accelerator.key_code()); |
| EXPECT_FALSE(accelerator.IsCtrlDown()); |
| EXPECT_TRUE(accelerator.IsShiftDown()); |
| EXPECT_TRUE(accelerator.IsAltDown()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(CommandsApiTest, ShortcutRemovedOnUpdate) { |
| base::ThreadRestrictions::ScopedAllowIO allow_io; |
| base::ScopedTempDir scoped_temp_dir; |
| EXPECT_TRUE(scoped_temp_dir.CreateUniqueTempDir()); |
| base::FilePath pem_path = test_data_dir_. |
| AppendASCII("keybinding").AppendASCII("keybinding.pem"); |
| base::FilePath path_v1 = |
| PackExtensionWithOptions(test_data_dir_.AppendASCII("keybinding") |
| .AppendASCII("update") |
| .AppendASCII("v1"), |
| scoped_temp_dir.GetPath().AppendASCII("v1.crx"), |
| pem_path, base::FilePath()); |
| base::FilePath path_v2_unassigned = PackExtensionWithOptions( |
| test_data_dir_.AppendASCII("keybinding") |
| .AppendASCII("update") |
| .AppendASCII("v2_unassigned"), |
| scoped_temp_dir.GetPath().AppendASCII("v2_unassigned.crx"), pem_path, |
| base::FilePath()); |
| |
| ExtensionRegistry* registry = ExtensionRegistry::Get(browser()->profile()); |
| CommandService* command_service = CommandService::Get(browser()->profile()); |
| |
| // Install v1 of the extension. |
| ASSERT_TRUE(InstallExtension(path_v1, 1)); |
| EXPECT_TRUE(registry->GetExtensionById(kId, ExtensionRegistry::ENABLED) != |
| NULL); |
| |
| // Verify it has a command of Alt+Shift+F. |
| ui::Accelerator accelerator = command_service->FindCommandByName( |
| kId, manifest_values::kBrowserActionCommandEvent).accelerator(); |
| EXPECT_EQ(ui::VKEY_F, accelerator.key_code()); |
| EXPECT_FALSE(accelerator.IsCtrlDown()); |
| EXPECT_TRUE(accelerator.IsShiftDown()); |
| EXPECT_TRUE(accelerator.IsAltDown()); |
| |
| // Update to version 2 without keybinding assigned. |
| EXPECT_TRUE(UpdateExtension(kId, path_v2_unassigned, 0)); |
| EXPECT_TRUE(registry->GetExtensionById(kId, ExtensionRegistry::ENABLED) != |
| NULL); |
| |
| // Verify the keybinding gets set to nothing. |
| accelerator = command_service->FindCommandByName( |
| kId, manifest_values::kBrowserActionCommandEvent).accelerator(); |
| EXPECT_EQ(ui::VKEY_UNKNOWN, accelerator.key_code()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(CommandsApiTest, |
| ShortcutAddedOnUpdateAfterBeingAssignedByUser) { |
| base::ThreadRestrictions::ScopedAllowIO allow_io; |
| base::ScopedTempDir scoped_temp_dir; |
| EXPECT_TRUE(scoped_temp_dir.CreateUniqueTempDir()); |
| base::FilePath pem_path = test_data_dir_. |
| AppendASCII("keybinding").AppendASCII("keybinding.pem"); |
| base::FilePath path_v1_unassigned = PackExtensionWithOptions( |
| test_data_dir_.AppendASCII("keybinding") |
| .AppendASCII("update") |
| .AppendASCII("v1_unassigned"), |
| scoped_temp_dir.GetPath().AppendASCII("v1_unassigned.crx"), pem_path, |
| base::FilePath()); |
| base::FilePath path_v2 = |
| PackExtensionWithOptions(test_data_dir_.AppendASCII("keybinding") |
| .AppendASCII("update") |
| .AppendASCII("v2"), |
| scoped_temp_dir.GetPath().AppendASCII("v2.crx"), |
| pem_path, base::FilePath()); |
| |
| ExtensionRegistry* registry = ExtensionRegistry::Get(browser()->profile()); |
| CommandService* command_service = CommandService::Get(browser()->profile()); |
| |
| // Install v1 of the extension without keybinding assigned. |
| ASSERT_TRUE(InstallExtension(path_v1_unassigned, 1)); |
| EXPECT_TRUE(registry->GetExtensionById(kId, ExtensionRegistry::ENABLED) != |
| NULL); |
| |
| // Verify it is set to nothing. |
| ui::Accelerator accelerator = command_service->FindCommandByName( |
| kId, manifest_values::kBrowserActionCommandEvent).accelerator(); |
| EXPECT_EQ(ui::VKEY_UNKNOWN, accelerator.key_code()); |
| |
| // Simulate the user setting the keybinding to Alt+Shift+G. |
| command_service->UpdateKeybindingPrefs( |
| kId, manifest_values::kBrowserActionCommandEvent, kAltShiftG); |
| |
| // Update to version 2 with keybinding. |
| EXPECT_TRUE(UpdateExtension(kId, path_v2, 0)); |
| EXPECT_TRUE(registry->GetExtensionById(kId, ExtensionRegistry::ENABLED) != |
| NULL); |
| |
| // Verify the previously-set keybinding is still set. |
| accelerator = command_service->FindCommandByName( |
| kId, manifest_values::kBrowserActionCommandEvent).accelerator(); |
| EXPECT_EQ(ui::VKEY_G, accelerator.key_code()); |
| EXPECT_FALSE(accelerator.IsCtrlDown()); |
| EXPECT_TRUE(accelerator.IsShiftDown()); |
| EXPECT_TRUE(accelerator.IsAltDown()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(CommandsApiTest, |
| ShortcutChangedOnUpdateAfterBeingReassignedByUser) { |
| base::ThreadRestrictions::ScopedAllowIO allow_io; |
| base::ScopedTempDir scoped_temp_dir; |
| EXPECT_TRUE(scoped_temp_dir.CreateUniqueTempDir()); |
| base::FilePath pem_path = test_data_dir_. |
| AppendASCII("keybinding").AppendASCII("keybinding.pem"); |
| base::FilePath path_v1 = |
| PackExtensionWithOptions(test_data_dir_.AppendASCII("keybinding") |
| .AppendASCII("update") |
| .AppendASCII("v1"), |
| scoped_temp_dir.GetPath().AppendASCII("v1.crx"), |
| pem_path, base::FilePath()); |
| base::FilePath path_v2_reassigned = PackExtensionWithOptions( |
| test_data_dir_.AppendASCII("keybinding") |
| .AppendASCII("update") |
| .AppendASCII("v2_reassigned"), |
| scoped_temp_dir.GetPath().AppendASCII("v2_reassigned.crx"), pem_path, |
| base::FilePath()); |
| |
| ExtensionRegistry* registry = ExtensionRegistry::Get(browser()->profile()); |
| CommandService* command_service = CommandService::Get(browser()->profile()); |
| |
| // Install v1 of the extension. |
| ASSERT_TRUE(InstallExtension(path_v1, 1)); |
| EXPECT_TRUE(registry->GetExtensionById(kId, ExtensionRegistry::ENABLED) != |
| NULL); |
| |
| // Verify it has a command of Alt+Shift+F. |
| ui::Accelerator accelerator = command_service->FindCommandByName( |
| kId, manifest_values::kBrowserActionCommandEvent).accelerator(); |
| EXPECT_EQ(ui::VKEY_F, accelerator.key_code()); |
| EXPECT_FALSE(accelerator.IsCtrlDown()); |
| EXPECT_TRUE(accelerator.IsShiftDown()); |
| EXPECT_TRUE(accelerator.IsAltDown()); |
| |
| // Simulate the user setting the keybinding to Alt+Shift+G. |
| command_service->UpdateKeybindingPrefs( |
| kId, manifest_values::kBrowserActionCommandEvent, kAltShiftG); |
| |
| // Update to version 2 with different keybinding assigned. |
| EXPECT_TRUE(UpdateExtension(kId, path_v2_reassigned, 0)); |
| EXPECT_TRUE(registry->GetExtensionById(kId, ExtensionRegistry::ENABLED) != |
| NULL); |
| |
| // Verify it has a command of Alt+Shift+G. |
| accelerator = command_service->FindCommandByName( |
| kId, manifest_values::kBrowserActionCommandEvent).accelerator(); |
| EXPECT_EQ(ui::VKEY_G, accelerator.key_code()); |
| EXPECT_FALSE(accelerator.IsCtrlDown()); |
| EXPECT_TRUE(accelerator.IsShiftDown()); |
| EXPECT_TRUE(accelerator.IsAltDown()); |
| } |
| |
| // Test that Media keys do not overwrite previous settings. |
| IN_PROC_BROWSER_TEST_F(CommandsApiTest, |
| MediaKeyShortcutChangedOnUpdateAfterBeingReassignedByUser) { |
| base::ThreadRestrictions::ScopedAllowIO allow_io; |
| base::ScopedTempDir scoped_temp_dir; |
| EXPECT_TRUE(scoped_temp_dir.CreateUniqueTempDir()); |
| base::FilePath pem_path = test_data_dir_. |
| AppendASCII("keybinding").AppendASCII("keybinding.pem"); |
| base::FilePath path_v1 = PackExtensionWithOptions( |
| test_data_dir_.AppendASCII("keybinding") |
| .AppendASCII("update") |
| .AppendASCII("mk_v1"), |
| scoped_temp_dir.GetPath().AppendASCII("mk_v1.crx"), pem_path, |
| base::FilePath()); |
| base::FilePath path_v2_reassigned = PackExtensionWithOptions( |
| test_data_dir_.AppendASCII("keybinding") |
| .AppendASCII("update") |
| .AppendASCII("mk_v2"), |
| scoped_temp_dir.GetPath().AppendASCII("mk_v2.crx"), pem_path, |
| base::FilePath()); |
| |
| ExtensionRegistry* registry = ExtensionRegistry::Get(browser()->profile()); |
| CommandService* command_service = CommandService::Get(browser()->profile()); |
| |
| // Install v1 of the extension. |
| ASSERT_TRUE(InstallExtension(path_v1, 1)); |
| EXPECT_TRUE(registry->GetExtensionById(kId, ExtensionRegistry::ENABLED) != |
| NULL); |
| |
| // Verify it has a command of MediaPlayPause. |
| ui::Accelerator accelerator = command_service->FindCommandByName( |
| kId, kMediaKeyTestCommand).accelerator(); |
| EXPECT_EQ(ui::VKEY_MEDIA_PLAY_PAUSE, accelerator.key_code()); |
| EXPECT_FALSE(accelerator.IsCtrlDown()); |
| EXPECT_FALSE(accelerator.IsShiftDown()); |
| EXPECT_FALSE(accelerator.IsAltDown()); |
| |
| // Simulate the user setting the keybinding to Alt+Shift+G. |
| command_service->UpdateKeybindingPrefs( |
| kId, kMediaKeyTestCommand, kAltShiftG); |
| |
| // Update to version 2 with different keybinding assigned. |
| EXPECT_TRUE(UpdateExtension(kId, path_v2_reassigned, 0)); |
| EXPECT_TRUE(registry->GetExtensionById(kId, ExtensionRegistry::ENABLED) != |
| NULL); |
| |
| // Verify it has a command of Alt+Shift+G. |
| accelerator = command_service->FindCommandByName( |
| kId, kMediaKeyTestCommand).accelerator(); |
| EXPECT_EQ(ui::VKEY_G, accelerator.key_code()); |
| EXPECT_FALSE(accelerator.IsCtrlDown()); |
| EXPECT_TRUE(accelerator.IsShiftDown()); |
| EXPECT_TRUE(accelerator.IsAltDown()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(CommandsApiTest, |
| ShortcutRemovedOnUpdateAfterBeingReassignedByUser) { |
| base::ThreadRestrictions::ScopedAllowIO allow_io; |
| base::ScopedTempDir scoped_temp_dir; |
| EXPECT_TRUE(scoped_temp_dir.CreateUniqueTempDir()); |
| base::FilePath pem_path = test_data_dir_. |
| AppendASCII("keybinding").AppendASCII("keybinding.pem"); |
| base::FilePath path_v1 = |
| PackExtensionWithOptions(test_data_dir_.AppendASCII("keybinding") |
| .AppendASCII("update") |
| .AppendASCII("v1"), |
| scoped_temp_dir.GetPath().AppendASCII("v1.crx"), |
| pem_path, base::FilePath()); |
| base::FilePath path_v2_unassigned = PackExtensionWithOptions( |
| test_data_dir_.AppendASCII("keybinding") |
| .AppendASCII("update") |
| .AppendASCII("v2_unassigned"), |
| scoped_temp_dir.GetPath().AppendASCII("v2_unassigned.crx"), pem_path, |
| base::FilePath()); |
| |
| ExtensionRegistry* registry = ExtensionRegistry::Get(browser()->profile()); |
| CommandService* command_service = CommandService::Get(browser()->profile()); |
| |
| // Install v1 of the extension. |
| ASSERT_TRUE(InstallExtension(path_v1, 1)); |
| EXPECT_TRUE(registry->GetExtensionById(kId, ExtensionRegistry::ENABLED) != |
| NULL); |
| |
| // Verify it has a command of Alt+Shift+F. |
| ui::Accelerator accelerator = command_service->FindCommandByName( |
| kId, manifest_values::kBrowserActionCommandEvent).accelerator(); |
| EXPECT_EQ(ui::VKEY_F, accelerator.key_code()); |
| EXPECT_FALSE(accelerator.IsCtrlDown()); |
| EXPECT_TRUE(accelerator.IsShiftDown()); |
| EXPECT_TRUE(accelerator.IsAltDown()); |
| |
| // Simulate the user reassigning the keybinding to Alt+Shift+G. |
| command_service->UpdateKeybindingPrefs( |
| kId, manifest_values::kBrowserActionCommandEvent, kAltShiftG); |
| |
| // Update to version 2 without keybinding assigned. |
| EXPECT_TRUE(UpdateExtension(kId, path_v2_unassigned, 0)); |
| EXPECT_TRUE(registry->GetExtensionById(kId, ExtensionRegistry::ENABLED) != |
| NULL); |
| |
| // Verify the keybinding is still set. |
| accelerator = command_service->FindCommandByName( |
| kId, manifest_values::kBrowserActionCommandEvent).accelerator(); |
| EXPECT_EQ(ui::VKEY_G, accelerator.key_code()); |
| EXPECT_FALSE(accelerator.IsCtrlDown()); |
| EXPECT_TRUE(accelerator.IsShiftDown()); |
| EXPECT_TRUE(accelerator.IsAltDown()); |
| } |
| |
| // |
| #if defined(OS_CHROMEOS) && !defined(NDEBUG) |
| // TODO(dtseng): Test times out on Chrome OS debug. See http://crbug.com/412456. |
| #define MAYBE_ContinuePropagation DISABLED_ContinuePropagation |
| #else |
| #define MAYBE_ContinuePropagation ContinuePropagation |
| #endif |
| |
| IN_PROC_BROWSER_TEST_F(CommandsApiTest, MAYBE_ContinuePropagation) { |
| // Setup the environment. |
| ASSERT_TRUE(embedded_test_server()->Start()); |
| ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser())); |
| ASSERT_TRUE(RunExtensionTest("keybinding/continue_propagation")) << message_; |
| ui_test_utils::NavigateToURL( |
| browser(), embedded_test_server()->GetURL("/extensions/test_file.txt")); |
| |
| ResultCatcher catcher; |
| |
| // Activate the shortcut (Ctrl+Shift+F). The page should capture the |
| // keystroke and not the extension since |onCommand| has no event listener |
| // initially. |
| ASSERT_TRUE(ui_test_utils::SendKeyPressSync( |
| browser(), ui::VKEY_F, true, true, false, false)); |
| ASSERT_TRUE(catcher.GetNextResult()); |
| |
| // Now, the extension should have added an |onCommand| event listener. |
| // Send the same key, but the |onCommand| listener should now receive it. |
| ASSERT_TRUE(ui_test_utils::SendKeyPressSync( |
| browser(), ui::VKEY_F, true, true, false, false)); |
| ASSERT_TRUE(catcher.GetNextResult()); |
| |
| // The extension should now have removed its |onCommand| event listener. |
| // Finally, the page should again receive the key. |
| ASSERT_TRUE(ui_test_utils::SendKeyPressSync( |
| browser(), ui::VKEY_F, true, true, false, false)); |
| ASSERT_TRUE(catcher.GetNextResult()); |
| } |
| |
| // Test is only applicable on Chrome OS. |
| #if defined(OS_CHROMEOS) |
| // http://crbug.com/410534 |
| #if defined(USE_OZONE) |
| #define MAYBE_ChromeOSConversions DISABLED_ChromeOSConversions |
| #else |
| #define MAYBE_ChromeOSConversions ChromeOSConversions |
| #endif |
| IN_PROC_BROWSER_TEST_F(CommandsApiTest, MAYBE_ChromeOSConversions) { |
| RunChromeOSConversionTest("keybinding/chromeos_conversions"); |
| } |
| #endif // OS_CHROMEOS |
| |
| // Make sure component extensions retain keybindings after removal then |
| // re-adding. |
| IN_PROC_BROWSER_TEST_F(CommandsApiTest, AddRemoveAddComponentExtension) { |
| ASSERT_TRUE(embedded_test_server()->Start()); |
| ASSERT_TRUE(RunComponentExtensionTest("keybinding/component")) << message_; |
| |
| extensions::ExtensionSystem::Get(browser()->profile()) |
| ->extension_service() |
| ->component_loader() |
| ->Remove("pkplfbidichfdicaijlchgnapepdginl"); |
| |
| ASSERT_TRUE(RunComponentExtensionTest("keybinding/component")) << message_; |
| } |
| |
| } // namespace extensions |