summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--apps/shell_window.cc30
-rw-r--r--apps/shell_window.h4
-rw-r--r--chrome/browser/apps/app_interactive_uitest.cc186
-rw-r--r--chrome/chrome_tests.gypi1
-rw-r--r--chrome/common/extensions/api/_permission_features.json4
-rw-r--r--chrome/common/extensions/permissions/chrome_api_permissions.cc1
-rw-r--r--chrome/common/extensions/permissions/permission_set_unittest.cc1
-rw-r--r--chrome/test/data/extensions/platform_apps/leave_fullscreen/main.html9
-rw-r--r--chrome/test/data/extensions/platform_apps/leave_fullscreen/main.js31
-rw-r--r--chrome/test/data/extensions/platform_apps/leave_fullscreen/manifest.json12
-rw-r--r--chrome/test/data/extensions/platform_apps/prevent_leave_fullscreen/main.html9
-rw-r--r--chrome/test/data/extensions/platform_apps/prevent_leave_fullscreen/main.js55
-rw-r--r--chrome/test/data/extensions/platform_apps/prevent_leave_fullscreen/manifest.json12
-rw-r--r--extensions/common/permissions/api_permission.h1
14 files changed, 356 insertions, 0 deletions
diff --git a/apps/shell_window.cc b/apps/shell_window.cc
index c50e532..75cd7cd 100644
--- a/apps/shell_window.cc
+++ b/apps/shell_window.cc
@@ -289,9 +289,39 @@ void ShellWindow::AddNewContents(WebContents* source,
initial_pos, user_gesture, was_blocked);
}
+bool ShellWindow::PreHandleKeyboardEvent(
+ content::WebContents* source,
+ const content::NativeWebKeyboardEvent& event,
+ bool* is_keyboard_shortcut) {
+ // Here, we can handle a key event before the content gets it. When we are
+ // fullscreen, we want to allow the user to leave when ESC is pressed.
+ // However, if the application has the "overrideEscFullscreen" permission, we
+ // should let it override that behavior.
+ // ::HandleKeyboardEvent() will only be called if the KeyEvent's default
+ // action is not prevented.
+ // Thus, we should handle the KeyEvent here only if the permission is not set.
+ if (event.windowsKeyCode == ui::VKEY_ESCAPE &&
+ (fullscreen_types_ != FULLSCREEN_TYPE_NONE) &&
+ !extension_->HasAPIPermission(APIPermission::kOverrideEscFullscreen)) {
+ Restore();
+ return true;
+ }
+
+ return false;
+}
+
void ShellWindow::HandleKeyboardEvent(
WebContents* source,
const content::NativeWebKeyboardEvent& event) {
+ // If the window is currently fullscreen, ESC should leave fullscreen.
+ // If this code is being called for ESC, that means that the KeyEvent's
+ // default behavior was not prevented by the content.
+ if (event.windowsKeyCode == ui::VKEY_ESCAPE &&
+ (fullscreen_types_ != FULLSCREEN_TYPE_NONE)) {
+ Restore();
+ return;
+ }
+
native_app_window_->HandleKeyboardEvent(event);
}
diff --git a/apps/shell_window.h b/apps/shell_window.h
index 86dafb5..e833f75 100644
--- a/apps/shell_window.h
+++ b/apps/shell_window.h
@@ -374,6 +374,10 @@ class ShellWindow : public content::NotificationObserver,
const gfx::Rect& initial_pos,
bool user_gesture,
bool* was_blocked) OVERRIDE;
+ virtual bool PreHandleKeyboardEvent(
+ content::WebContents* source,
+ const content::NativeWebKeyboardEvent& event,
+ bool* is_keyboard_shortcut) OVERRIDE;
virtual void HandleKeyboardEvent(
content::WebContents* source,
const content::NativeWebKeyboardEvent& event) OVERRIDE;
diff --git a/chrome/browser/apps/app_interactive_uitest.cc b/chrome/browser/apps/app_interactive_uitest.cc
new file mode 100644
index 0000000..8a6c96d
--- /dev/null
+++ b/chrome/browser/apps/app_interactive_uitest.cc
@@ -0,0 +1,186 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "apps/ui/native_app_window.h"
+#include "chrome/browser/apps/app_browsertest_util.h"
+#include "chrome/browser/extensions/extension_test_message_listener.h"
+#include "chrome/test/base/interactive_test_utils.h"
+
+using namespace apps;
+
+// This test does not work on Linux Aura yet. It might be because the fullscreen
+// window is not correctly focused or because key events are not correctly sent.
+#if !(defined(OS_LINUX) && defined(USE_AURA))
+
+// This test is also highly flaky on MacOS X.
+#if !defined(OS_MACOSX)
+
+// Helper class that has to be created in the stack to check if the fullscreen
+// setting of a NativeWindow has changed since the creation of the object.
+class FullscreenChangeWaiter {
+ public:
+ explicit FullscreenChangeWaiter(NativeAppWindow* window)
+ : window_(window),
+ initial_fullscreen_state_(window_->IsFullscreen()) {}
+
+ void Wait() {
+ while (initial_fullscreen_state_ != window_->IsFullscreen())
+ content::RunAllPendingInMessageLoop();
+ }
+
+ private:
+ NativeAppWindow* window_;
+ bool initial_fullscreen_state_;
+
+ DISALLOW_COPY_AND_ASSIGN(FullscreenChangeWaiter);
+};
+
+class AppInteractiveTest : public extensions::PlatformAppBrowserTest {
+ public:
+ bool SimulateKeyPress(ui::KeyboardCode key) {
+ return ui_test_utils::SendKeyPressToWindowSync(
+ GetFirstShellWindow()->GetNativeWindow(),
+ key,
+ false,
+ false,
+ false,
+ false);
+ }
+};
+
+IN_PROC_BROWSER_TEST_F(AppInteractiveTest, ESCLeavesFullscreenWindow) {
+ ExtensionTestMessageListener launched_listener("Launched", true);
+ LoadAndLaunchPlatformApp("leave_fullscreen");
+ ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
+
+ // When receiving the reply, the application will try to go fullscreen using
+ // the Window API but there is no synchronous way to know if that actually
+ // succeeded. Also, failure will not be notified. A failure case will only be
+ // known with a timeout.
+ {
+ FullscreenChangeWaiter fs_changed(GetFirstShellWindow()->GetBaseWindow());
+
+ launched_listener.Reply("window");
+
+ fs_changed.Wait();
+ }
+
+ // Same idea as above but for leaving fullscreen. Fullscreen mode should be
+ // left when ESC is received.
+ {
+ FullscreenChangeWaiter fs_changed(GetFirstShellWindow()->GetBaseWindow());
+
+ ASSERT_TRUE(SimulateKeyPress(ui::VKEY_ESCAPE));
+
+ fs_changed.Wait();
+ }
+}
+
+IN_PROC_BROWSER_TEST_F(AppInteractiveTest, ESCLeavesFullscreenDOM) {
+ ExtensionTestMessageListener launched_listener("Launched", true);
+ LoadAndLaunchPlatformApp("leave_fullscreen");
+ ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
+
+ launched_listener.Reply("dom");
+
+ // Because the DOM way to go fullscreen requires user gesture, we simulate a
+ // key event to get the window entering in fullscreen mode. The reply will
+ // make the window listen for the key event. The reply will be sent to the
+ // renderer process before the keypress and should be received in that order.
+ // When receiving the key event, the application will try to go fullscreen
+ // using the Window API but there is no synchronous way to know if that
+ // actually succeeded. Also, failure will not be notified. A failure case will
+ // only be known with a timeout.
+ {
+ FullscreenChangeWaiter fs_changed(GetFirstShellWindow()->GetBaseWindow());
+
+ ASSERT_TRUE(SimulateKeyPress(ui::VKEY_A));
+
+ fs_changed.Wait();
+ }
+
+ // Same idea as above but for leaving fullscreen. Fullscreen mode should be
+ // left when ESC is received.
+ {
+ FullscreenChangeWaiter fs_changed(GetFirstShellWindow()->GetBaseWindow());
+
+ ASSERT_TRUE(SimulateKeyPress(ui::VKEY_ESCAPE));
+
+ fs_changed.Wait();
+ }
+}
+
+IN_PROC_BROWSER_TEST_F(AppInteractiveTest, ESCDoesNotLeaveFullscreenWindow) {
+ ExtensionTestMessageListener launched_listener("Launched", true);
+ LoadAndLaunchPlatformApp("prevent_leave_fullscreen");
+ ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
+
+ // When receiving the reply, the application will try to go fullscreen using
+ // the Window API but there is no synchronous way to know if that actually
+ // succeeded. Also, failure will not be notified. A failure case will only be
+ // known with a timeout.
+ {
+ FullscreenChangeWaiter fs_changed(GetFirstShellWindow()->GetBaseWindow());
+
+ launched_listener.Reply("window");
+
+ fs_changed.Wait();
+ }
+
+ ASSERT_TRUE(SimulateKeyPress(ui::VKEY_ESCAPE));
+
+ ExtensionTestMessageListener second_key_listener("B_KEY_RECEIVED", false);
+
+ ASSERT_TRUE(SimulateKeyPress(ui::VKEY_B));
+
+ ASSERT_TRUE(second_key_listener.WaitUntilSatisfied());
+
+ // We assume that at that point, if we had to leave fullscreen, we should be.
+ // However, by nature, we can not guarantee that and given that we do test
+ // that nothing happens, we might end up with random-success when the feature
+ // is broken.
+ EXPECT_TRUE(GetFirstShellWindow()->GetBaseWindow()->IsFullscreen());
+}
+
+IN_PROC_BROWSER_TEST_F(AppInteractiveTest, ESCDoesNotLeaveFullscreenDOM) {
+ ExtensionTestMessageListener launched_listener("Launched", true);
+ LoadAndLaunchPlatformApp("prevent_leave_fullscreen");
+ ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
+
+ launched_listener.Reply("dom");
+
+ // Because the DOM way to go fullscreen requires user gesture, we simulate a
+ // key event to get the window entering in fullscreen mode. The reply will
+ // make the window listen for the key event. The reply will be sent to the
+ // renderer process before the keypress and should be received in that order.
+ // When receiving the key event, the application will try to go fullscreen
+ // using the Window API but there is no synchronous way to know if that
+ // actually succeeded. Also, failure will not be notified. A failure case will
+ // only be known with a timeout.
+ {
+ FullscreenChangeWaiter fs_changed(GetFirstShellWindow()->GetBaseWindow());
+
+ ASSERT_TRUE(SimulateKeyPress(ui::VKEY_A));
+
+ fs_changed.Wait();
+ }
+
+ ASSERT_TRUE(SimulateKeyPress(ui::VKEY_ESCAPE));
+
+ ExtensionTestMessageListener second_key_listener("B_KEY_RECEIVED", false);
+
+ ASSERT_TRUE(SimulateKeyPress(ui::VKEY_B));
+
+ ASSERT_TRUE(second_key_listener.WaitUntilSatisfied());
+
+ // We assume that at that point, if we had to leave fullscreen, we should be.
+ // However, by nature, we can not guarantee that and given that we do test
+ // that nothing happens, we might end up with random-success when the feature
+ // is broken.
+ EXPECT_TRUE(GetFirstShellWindow()->GetBaseWindow()->IsFullscreen());
+}
+
+#endif // !(defined(OS_MACOSX))
+
+#endif // !(defined(OS_LINUX) && defined(USE_AURA))
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index cd8764a..a8eb09f 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -160,6 +160,7 @@
'../ui/views/widget/widget_interactive_uitest.cc',
'browser/apps/app_browsertest_util.cc',
'browser/apps/app_browsertest_util.h',
+ 'browser/apps/app_interactive_uitest.cc',
'browser/apps/web_view_interactive_browsertest.cc',
'browser/autofill/autofill_interactive_uitest.cc',
'browser/browser_keyevents_browsertest.cc',
diff --git a/chrome/common/extensions/api/_permission_features.json b/chrome/common/extensions/api/_permission_features.json
index c903baa..4ffc8b6 100644
--- a/chrome/common/extensions/api/_permission_features.json
+++ b/chrome/common/extensions/api/_permission_features.json
@@ -593,6 +593,10 @@
"extension", "legacy_packaged_app", "hosted_app", "platform_app"
]
},
+ "overrideEscFullscreen": {
+ "channel": "stable",
+ "extension_types": ["platform_app"]
+ },
"echoPrivate": {
"channel": "stable",
"extension_types": ["extension", "legacy_packaged_app"],
diff --git a/chrome/common/extensions/permissions/chrome_api_permissions.cc b/chrome/common/extensions/permissions/chrome_api_permissions.cc
index 10dbaef1..3496cdd 100644
--- a/chrome/common/extensions/permissions/chrome_api_permissions.cc
+++ b/chrome/common/extensions/permissions/chrome_api_permissions.cc
@@ -354,6 +354,7 @@ std::vector<APIPermissionInfo*> ChromeAPIPermissions::GetAllPermissions()
{ APIPermission::kFullscreen, "fullscreen" },
{ APIPermission::kAudio, "audio" },
{ APIPermission::kWebRtc, "webrtc" },
+ { APIPermission::kOverrideEscFullscreen, "overrideEscFullscreen" },
// Settings override permissions.
{ APIPermission::kHomepage, "homepage",
diff --git a/chrome/common/extensions/permissions/permission_set_unittest.cc b/chrome/common/extensions/permissions/permission_set_unittest.cc
index 4951782..d81d4fb 100644
--- a/chrome/common/extensions/permissions/permission_set_unittest.cc
+++ b/chrome/common/extensions/permissions/permission_set_unittest.cc
@@ -683,6 +683,7 @@ TEST(PermissionsTest, PermissionMessages) {
skip.insert(APIPermission::kUnlimitedStorage);
skip.insert(APIPermission::kWebRtc);
skip.insert(APIPermission::kWebView);
+ skip.insert(APIPermission::kOverrideEscFullscreen);
// TODO(erikkay) add a string for this permission.
skip.insert(APIPermission::kBackground);
diff --git a/chrome/test/data/extensions/platform_apps/leave_fullscreen/main.html b/chrome/test/data/extensions/platform_apps/leave_fullscreen/main.html
new file mode 100644
index 0000000..831d97e
--- /dev/null
+++ b/chrome/test/data/extensions/platform_apps/leave_fullscreen/main.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>fullscreen</title>
+</head>
+<body>
+ foobar
+</body>
+</html>
diff --git a/chrome/test/data/extensions/platform_apps/leave_fullscreen/main.js b/chrome/test/data/extensions/platform_apps/leave_fullscreen/main.js
new file mode 100644
index 0000000..109bccf
--- /dev/null
+++ b/chrome/test/data/extensions/platform_apps/leave_fullscreen/main.js
@@ -0,0 +1,31 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+chrome.app.runtime.onLaunched.addListener(function() {
+ chrome.app.window.create('main.html', {}, function(win) {
+ // The following key events handler should have no effect because the
+ // application does not have the 'overrideEscFullscreen' permission.
+ win.contentWindow.document.addEventListener('keydown', function(e) {
+ e.preventDefault();
+ });
+ win.contentWindow.document.addEventListener('keyup', function(e) {
+ e.preventDefault();
+ });
+
+ chrome.test.sendMessage('Launched', function(reply) {
+ switch (reply) {
+ case 'window':
+ win.fullscreen();
+ break;
+ case 'dom':
+ win.contentWindow.document.addEventListener('keydown', function() {
+ win.contentWindow.document.removeEventListener('keydown',
+ arguments.callee);
+ win.contentWindow.document.body.webkitRequestFullscreen();
+ });
+ break;
+ }
+ });
+ });
+});
diff --git a/chrome/test/data/extensions/platform_apps/leave_fullscreen/manifest.json b/chrome/test/data/extensions/platform_apps/leave_fullscreen/manifest.json
new file mode 100644
index 0000000..5bf766f
--- /dev/null
+++ b/chrome/test/data/extensions/platform_apps/leave_fullscreen/manifest.json
@@ -0,0 +1,12 @@
+{
+ "name": "Test app for leaving fullscreen rules",
+ "version": "1",
+ "app": {
+ "background": {
+ "scripts": ["main.js"]
+ }
+ },
+ "permissions": [
+ "fullscreen"
+ ]
+}
diff --git a/chrome/test/data/extensions/platform_apps/prevent_leave_fullscreen/main.html b/chrome/test/data/extensions/platform_apps/prevent_leave_fullscreen/main.html
new file mode 100644
index 0000000..831d97e
--- /dev/null
+++ b/chrome/test/data/extensions/platform_apps/prevent_leave_fullscreen/main.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>fullscreen</title>
+</head>
+<body>
+ foobar
+</body>
+</html>
diff --git a/chrome/test/data/extensions/platform_apps/prevent_leave_fullscreen/main.js b/chrome/test/data/extensions/platform_apps/prevent_leave_fullscreen/main.js
new file mode 100644
index 0000000..e206710
--- /dev/null
+++ b/chrome/test/data/extensions/platform_apps/prevent_leave_fullscreen/main.js
@@ -0,0 +1,55 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+chrome.app.runtime.onLaunched.addListener(function() {
+ chrome.app.window.create('main.html', {}, function(win) {
+ // The following key events handler will prevent the default behavior for
+ // the ESC key, thus will prevent the ESC key to leave fullscreen.
+ win.contentWindow.document.addEventListener('keydown', function(e) {
+ e.preventDefault();
+ });
+ win.contentWindow.document.addEventListener('keyup', function(e) {
+ e.preventDefault();
+ });
+
+ chrome.test.sendMessage('Launched', function(reply) {
+ var doc = win.contentWindow.document;
+
+ switch (reply) {
+ case 'window':
+ doc.addEventListener('keydown', function(e) {
+ if (e.keyCode != 66) // 'b'
+ return;
+ doc.removeEventListener('keydown', arguments.callee);
+ // We do one trip to the event loop to increase the chances that
+ // fullscreen could have been left before the message is received.
+ setTimeout(function() {
+ chrome.test.sendMessage('B_KEY_RECEIVED');
+ });
+ });
+ win.fullscreen();
+ break;
+
+ case 'dom':
+ doc.addEventListener('keydown', function() {
+ doc.removeEventListener('keydown', arguments.callee);
+
+ doc.addEventListener('keydown', function(e) {
+ if (e.keyCode != 66) // 'b'
+ return;
+ doc.removeEventListener('keydown', arguments.callee);
+ // We do one trip to the event loop to increase the chances that
+ // fullscreen could have been left before the message is received.
+ setTimeout(function() {
+ chrome.test.sendMessage('B_KEY_RECEIVED');
+ });
+ });
+
+ doc.body.webkitRequestFullscreen();
+ });
+ break;
+ }
+ });
+ });
+});
diff --git a/chrome/test/data/extensions/platform_apps/prevent_leave_fullscreen/manifest.json b/chrome/test/data/extensions/platform_apps/prevent_leave_fullscreen/manifest.json
new file mode 100644
index 0000000..8cd9d23
--- /dev/null
+++ b/chrome/test/data/extensions/platform_apps/prevent_leave_fullscreen/manifest.json
@@ -0,0 +1,12 @@
+{
+ "name": "Test app for leaving fullscreen rules",
+ "version": "1",
+ "app": {
+ "background": {
+ "scripts": ["main.js"]
+ }
+ },
+ "permissions": [
+ "fullscreen", "overrideEscFullscreen"
+ ]
+}
diff --git a/extensions/common/permissions/api_permission.h b/extensions/common/permissions/api_permission.h
index e0054ae..78fa428 100644
--- a/extensions/common/permissions/api_permission.h
+++ b/extensions/common/permissions/api_permission.h
@@ -112,6 +112,7 @@ class APIPermission {
kNativeMessaging,
kNetworkingPrivate,
kNotification,
+ kOverrideEscFullscreen,
kPageCapture,
kPointerLock,
kPlugin,