summaryrefslogtreecommitdiffstats
path: root/apps
diff options
context:
space:
mode:
authortmdiep@chromium.org <tmdiep@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-11-25 23:32:51 +0000
committertmdiep@chromium.org <tmdiep@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-11-25 23:32:51 +0000
commit007c1194fe848b3483e3acbbed56b986166cf2f1 (patch)
tree9e16af11bb4495075960b0091f8b90d08c58abb6 /apps
parent7bf7c83364aa58895bc27e966c7914c830eaaf3c (diff)
downloadchromium_src-007c1194fe848b3483e3acbbed56b986166cf2f1.zip
chromium_src-007c1194fe848b3483e3acbbed56b986166cf2f1.tar.gz
chromium_src-007c1194fe848b3483e3acbbed56b986166cf2f1.tar.bz2
Fullscreen app windows cannot have always-on-top enabled
An app window in fullscreen mode should not also be always-on-top. This is because it makes it difficult to alt+tab to another window, which is both annoying from a UX perspective and a security issue. To mitigate this: The always-on-top property is temporarily switched off when the window enters fullscreen, but then reinstated when the window is restored. To be consistent, if a window is fullscreen and an attempt is made to set it always-on-top, we only apply the always-on-top property when the window exits fullscreen. This patch also changes the value returned by the chrome.app.window IsAlwaysOnTop() function. It previously returned the actual state of the window, but now returns the desired state, i.e. the value will be true even when the property is switched off in fullscreen mode. BUG=320103, 171597 TESTS=browser_tests (PlatformAppBrowserTest.WindowsApiAlwaysOnTop*). interactive_ui_tests (ShellWindowTest.*AlwaysOnTop*). Also test manually using Window State chrome sample app using app window API fullscreen and HTML5 fullscreen. Review URL: https://codereview.chromium.org/76993004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@237178 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'apps')
-rw-r--r--apps/app_window_contents.cc2
-rw-r--r--apps/shell_window.cc53
-rw-r--r--apps/shell_window.h17
-rw-r--r--apps/shell_window_interactive_uitest.cc221
4 files changed, 287 insertions, 6 deletions
diff --git a/apps/app_window_contents.cc b/apps/app_window_contents.cc
index 751ccc2..22d0da1 100644
--- a/apps/app_window_contents.cc
+++ b/apps/app_window_contents.cc
@@ -98,7 +98,7 @@ void AppWindowContents::NativeWindowChanged(
native_app_window->IsFullscreenOrPending());
dictionary->SetBoolean("minimized", native_app_window->IsMinimized());
dictionary->SetBoolean("maximized", native_app_window->IsMaximized());
- dictionary->SetBoolean("alwaysOnTop", native_app_window->IsAlwaysOnTop());
+ dictionary->SetBoolean("alwaysOnTop", host_->IsAlwaysOnTop());
const ShellWindow::SizeConstraints& size_constraints =
host_->size_constraints();
diff --git a/apps/shell_window.cc b/apps/shell_window.cc
index 2c0b3fac..aade475 100644
--- a/apps/shell_window.cc
+++ b/apps/shell_window.cc
@@ -143,7 +143,8 @@ ShellWindow::ShellWindow(Profile* profile,
image_loader_ptr_factory_(this),
fullscreen_types_(FULLSCREEN_TYPE_NONE),
show_on_first_paint_(false),
- first_paint_complete_(false) {
+ first_paint_complete_(false),
+ cached_always_on_top_(false) {
}
void ShellWindow::Init(const GURL& url,
@@ -172,6 +173,12 @@ void ShellWindow::Init(const GURL& url,
window_key_ = new_params.window_key;
size_constraints_ = SizeConstraints(new_params.minimum_size,
new_params.maximum_size);
+
+ // Windows cannot be always-on-top in fullscreen mode for security reasons.
+ cached_always_on_top_ = new_params.always_on_top;
+ if (new_params.state == ui::SHOW_STATE_FULLSCREEN)
+ new_params.always_on_top = false;
+
native_app_window_.reset(delegate_->CreateNativeAppWindow(this, new_params));
if (!new_params.hidden) {
@@ -404,7 +411,7 @@ void ShellWindow::Fullscreen() {
return;
#endif
fullscreen_types_ |= FULLSCREEN_TYPE_WINDOW_API;
- GetBaseWindow()->SetFullscreen(fullscreen_types_);
+ SetNativeWindowFullscreen(fullscreen_types_);
}
void ShellWindow::Maximize() {
@@ -418,7 +425,7 @@ void ShellWindow::Minimize() {
void ShellWindow::Restore() {
if (fullscreen_types_ != FULLSCREEN_TYPE_NONE) {
fullscreen_types_ = FULLSCREEN_TYPE_NONE;
- GetBaseWindow()->SetFullscreen(fullscreen_types_);
+ SetNativeWindowFullscreen(fullscreen_types_);
} else {
GetBaseWindow()->Restore();
}
@@ -431,7 +438,7 @@ void ShellWindow::OSFullscreen() {
return;
#endif
fullscreen_types_ |= FULLSCREEN_TYPE_OS;
- GetBaseWindow()->SetFullscreen(fullscreen_types_);
+ SetNativeWindowFullscreen(fullscreen_types_);
}
void ShellWindow::SetMinimumSize(const gfx::Size& min_size) {
@@ -474,6 +481,25 @@ void ShellWindow::Hide() {
GetBaseWindow()->Hide();
}
+void ShellWindow::SetAlwaysOnTop(bool always_on_top) {
+ if (cached_always_on_top_ == always_on_top)
+ return;
+
+ cached_always_on_top_ = always_on_top;
+
+ // As a security measure, do not allow fullscreen windows to be on top.
+ // The property will be applied when the window exits fullscreen.
+ bool fullscreen = (fullscreen_types_ != FULLSCREEN_TYPE_NONE);
+ if (!fullscreen)
+ native_app_window_->SetAlwaysOnTop(always_on_top);
+
+ OnNativeWindowChanged();
+}
+
+bool ShellWindow::IsAlwaysOnTop() const {
+ return cached_always_on_top_;
+}
+
//------------------------------------------------------------------------------
// Private methods
@@ -532,6 +558,23 @@ void ShellWindow::OnSizeConstraintsChanged() {
OnNativeWindowChanged();
}
+void ShellWindow::SetNativeWindowFullscreen(int fullscreen_types) {
+ native_app_window_->SetFullscreen(fullscreen_types);
+
+ if (!cached_always_on_top_)
+ return;
+
+ bool is_on_top = native_app_window_->IsAlwaysOnTop();
+ bool fullscreen = (fullscreen_types != FULLSCREEN_TYPE_NONE);
+ if (fullscreen && is_on_top) {
+ // When entering fullscreen, ensure windows are not always-on-top.
+ native_app_window_->SetAlwaysOnTop(false);
+ } else if (!fullscreen && !is_on_top) {
+ // When exiting fullscreen, reinstate always-on-top.
+ native_app_window_->SetAlwaysOnTop(true);
+ }
+}
+
void ShellWindow::CloseContents(WebContents* contents) {
native_app_window_->Close();
}
@@ -597,7 +640,7 @@ void ShellWindow::ToggleFullscreenModeForTab(content::WebContents* source,
fullscreen_types_ |= FULLSCREEN_TYPE_HTML_API;
else
fullscreen_types_ &= ~FULLSCREEN_TYPE_HTML_API;
- GetBaseWindow()->SetFullscreen(fullscreen_types_);
+ SetNativeWindowFullscreen(fullscreen_types_);
}
bool ShellWindow::IsFullscreenForTabOrPending(
diff --git a/apps/shell_window.h b/apps/shell_window.h
index 9890038..d8d3964 100644
--- a/apps/shell_window.h
+++ b/apps/shell_window.h
@@ -328,6 +328,15 @@ class ShellWindow : public content::NotificationObserver,
return size_constraints_;
}
+ // Set whether the window should stay above other windows which are not
+ // configured to be always-on-top.
+ void SetAlwaysOnTop(bool always_on_top);
+
+ // Whether the always-on-top property has been set by the chrome.app.window
+ // API. Note that the actual value of this property in the native app window
+ // will be false in fullscreen mode.
+ bool IsAlwaysOnTop() const;
+
protected:
virtual ~ShellWindow();
@@ -414,6 +423,9 @@ class ShellWindow : public content::NotificationObserver,
// Called when size_constraints is changed.
void OnSizeConstraintsChanged();
+ // Set the fullscreen state in the native app window.
+ void SetNativeWindowFullscreen(int fullscreen_types);
+
// extensions::ExtensionKeybindingRegistry::Delegate implementation.
virtual extensions::ActiveTabPermissionGranter*
GetActiveTabPermissionGranter() OVERRIDE;
@@ -478,6 +490,11 @@ class ShellWindow : public content::NotificationObserver,
// Whether the delayed Show() call was for an active or inactive window.
ShowType delayed_show_type_;
+ // Cache the desired value of the always-on-top property. When windows enter
+ // fullscreen, this property will be automatically switched off for security
+ // reasons. It is reinstated when the window exits fullscreen.
+ bool cached_always_on_top_;
+
DISALLOW_COPY_AND_ASSIGN(ShellWindow);
};
diff --git a/apps/shell_window_interactive_uitest.cc b/apps/shell_window_interactive_uitest.cc
new file mode 100644
index 0000000..69f5563
--- /dev/null
+++ b/apps/shell_window_interactive_uitest.cc
@@ -0,0 +1,221 @@
+// 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"
+
+using extensions::PlatformAppBrowserTest;
+using extensions::Extension;
+
+namespace apps {
+
+namespace {
+
+const char kDefaultTestApp[] = "shell_window/generic";
+
+class ShellWindowTest : public PlatformAppBrowserTest {
+ protected:
+ // Load the test app and create a window. The window must be closed by the
+ // caller in order to terminate the test.
+ // |app_path| is the name of the test.
+ // |window_create_options| are the options that will be passed to
+ // chrome.app.window.create() in the test app.
+ ShellWindow* OpenWindow(const char* app_path,
+ const char* window_create_options) {
+ ExtensionTestMessageListener launched_listener("launched", true);
+ ExtensionTestMessageListener loaded_listener("window_loaded", false);
+
+ // Load and launch the test app.
+ const Extension* extension = LoadAndLaunchPlatformApp(app_path);
+ EXPECT_TRUE(extension);
+ EXPECT_TRUE(launched_listener.WaitUntilSatisfied());
+
+ // Send the options for window creation.
+ launched_listener.Reply(window_create_options);
+
+ // Wait for the window to be opened and loaded.
+ EXPECT_TRUE(loaded_listener.WaitUntilSatisfied());
+
+ EXPECT_EQ(1U, GetShellWindowCount());
+ ShellWindow* shell_window = GetFirstShellWindow();
+ return shell_window;
+ }
+
+ void CheckAlwaysOnTopToFullscreen(ShellWindow* window) {
+ ASSERT_TRUE(window->GetBaseWindow()->IsAlwaysOnTop());
+
+ // The always-on-top property should be temporarily disabled when the window
+ // enters fullscreen.
+ window->Fullscreen();
+ EXPECT_FALSE(window->GetBaseWindow()->IsAlwaysOnTop());
+
+ // From the API's point of view, the always-on-top property is enabled.
+ EXPECT_TRUE(window->IsAlwaysOnTop());
+
+ // The always-on-top property is restored when the window exits fullscreen.
+ window->Restore();
+ EXPECT_TRUE(window->GetBaseWindow()->IsAlwaysOnTop());
+ }
+
+ void CheckNormalToFullscreen(ShellWindow* window) {
+ // If the always-on-top property is false, it should remain this way when
+ // entering and exiting fullscreen mode.
+ ASSERT_FALSE(window->GetBaseWindow()->IsAlwaysOnTop());
+ window->Fullscreen();
+ EXPECT_FALSE(window->GetBaseWindow()->IsAlwaysOnTop());
+ window->Restore();
+ EXPECT_FALSE(window->GetBaseWindow()->IsAlwaysOnTop());
+ }
+
+ void CheckFullscreenToAlwaysOnTop(ShellWindow* window) {
+ ASSERT_TRUE(window->GetBaseWindow()->IsFullscreenOrPending());
+
+ // Now enable always-on-top at runtime and ensure the property does not get
+ // applied immediately because the window is in fullscreen mode.
+ window->SetAlwaysOnTop(true);
+ EXPECT_FALSE(window->GetBaseWindow()->IsAlwaysOnTop());
+
+ // From the API's point of view, the always-on-top property is enabled.
+ EXPECT_TRUE(window->IsAlwaysOnTop());
+
+ // Ensure the always-on-top property is applied when exiting fullscreen.
+ window->Restore();
+ EXPECT_TRUE(window->GetBaseWindow()->IsAlwaysOnTop());
+ }
+};
+
+} // namespace
+
+// Tests are flaky on Mac as transitioning to fullscreen is not instantaneous
+// and throws errors when entering/exiting fullscreen too quickly.
+#if defined(OS_MACOSX)
+#define MAYBE_InitAlwaysOnTopToFullscreen DISABLED_InitAlwaysOnTopToFullscreen
+#else
+#define MAYBE_InitAlwaysOnTopToFullscreen InitAlwaysOnTopToFullscreen
+#endif
+
+// Tests a window created with always-on-top enabled and ensures that the
+// property is temporarily switched off when entering fullscreen mode.
+IN_PROC_BROWSER_TEST_F(ShellWindowTest, MAYBE_InitAlwaysOnTopToFullscreen) {
+ ShellWindow* window = OpenWindow(
+ kDefaultTestApp, "{ \"alwaysOnTop\": true }");
+ ASSERT_TRUE(window);
+ CheckAlwaysOnTopToFullscreen(window);
+
+ window->SetAlwaysOnTop(false);
+ CheckNormalToFullscreen(window);
+
+ CloseShellWindow(window);
+}
+
+#if defined(OS_MACOSX)
+#define MAYBE_RuntimeAlwaysOnTopToFullscreen DISABLED_RuntimeAlwaysOnTopToFullscreen
+#else
+#define MAYBE_RuntimeAlwaysOnTopToFullscreen RuntimeAlwaysOnTopToFullscreen
+#endif
+
+// Tests a window with always-on-top enabled at runtime and ensures that the
+// property is temporarily switched off when entering fullscreen mode.
+IN_PROC_BROWSER_TEST_F(ShellWindowTest, MAYBE_RuntimeAlwaysOnTopToFullscreen) {
+ ShellWindow* window = OpenWindow(
+ kDefaultTestApp, "{}");
+ ASSERT_TRUE(window);
+ CheckNormalToFullscreen(window);
+
+ window->SetAlwaysOnTop(true);
+ CheckAlwaysOnTopToFullscreen(window);
+
+ CloseShellWindow(window);
+}
+
+#if defined(OS_MACOSX)
+#define MAYBE_InitFullscreenToAlwaysOnTop DISABLED_InitFullscreenToAlwaysOnTop
+#else
+#define MAYBE_InitFullscreenToAlwaysOnTop InitFullscreenToAlwaysOnTop
+#endif
+
+// Tests a window created initially in fullscreen mode and ensures that the
+// always-on-top property does not get applied until it exits fullscreen.
+IN_PROC_BROWSER_TEST_F(ShellWindowTest, MAYBE_InitFullscreenToAlwaysOnTop) {
+ ShellWindow* window = OpenWindow(
+ kDefaultTestApp, "{ \"state\": \"fullscreen\" }");
+ ASSERT_TRUE(window);
+ CheckFullscreenToAlwaysOnTop(window);
+
+ CloseShellWindow(window);
+}
+
+#if defined(OS_MACOSX)
+#define MAYBE_RuntimeFullscreenToAlwaysOnTop DISABLED_RuntimeFullscreenToAlwaysOnTop
+#else
+#define MAYBE_RuntimeFullscreenToAlwaysOnTop RuntimeFullscreenToAlwaysOnTop
+#endif
+
+// Tests a window that enters fullscreen mode at runtime and ensures that the
+// always-on-top property does not get applied until it exits fullscreen.
+IN_PROC_BROWSER_TEST_F(ShellWindowTest, MAYBE_RuntimeFullscreenToAlwaysOnTop) {
+ ShellWindow* window = OpenWindow(
+ kDefaultTestApp, "{}");
+ ASSERT_TRUE(window);
+
+ window->Fullscreen();
+ CheckFullscreenToAlwaysOnTop(window);
+
+ CloseShellWindow(window);
+}
+
+#if defined(OS_MACOSX)
+#define MAYBE_InitFullscreenAndAlwaysOnTop DISABLED_InitFullscreenAndAlwaysOnTop
+#else
+#define MAYBE_InitFullscreenAndAlwaysOnTop InitFullscreenAndAlwaysOnTop
+#endif
+
+// Tests a window created with both fullscreen and always-on-top enabled. Ensure
+// that always-on-top is only applied when the window exits fullscreen.
+IN_PROC_BROWSER_TEST_F(ShellWindowTest, MAYBE_InitFullscreenAndAlwaysOnTop) {
+ ShellWindow* window = OpenWindow(
+ kDefaultTestApp, "{ \"alwaysOnTop\": true, \"state\": \"fullscreen\" }");
+ ASSERT_TRUE(window);
+
+ EXPECT_TRUE(window->GetBaseWindow()->IsFullscreenOrPending());
+ EXPECT_FALSE(window->GetBaseWindow()->IsAlwaysOnTop());
+
+ // From the API's point of view, the always-on-top property is enabled.
+ EXPECT_TRUE(window->IsAlwaysOnTop());
+
+ window->Restore();
+ EXPECT_TRUE(window->GetBaseWindow()->IsAlwaysOnTop());
+
+ CloseShellWindow(window);
+}
+
+#if defined(OS_MACOSX)
+#define MAYBE_DisableAlwaysOnTopInFullscreen DISABLED_DisableAlwaysOnTopInFullscreen
+#else
+#define MAYBE_DisableAlwaysOnTopInFullscreen DisableAlwaysOnTopInFullscreen
+#endif
+
+// Tests a window created with always-on-top enabled, but then disabled while
+// in fullscreen mode. After exiting fullscreen, always-on-top should remain
+// disabled.
+IN_PROC_BROWSER_TEST_F(ShellWindowTest, MAYBE_DisableAlwaysOnTopInFullscreen) {
+ ShellWindow* window = OpenWindow(
+ kDefaultTestApp, "{ \"alwaysOnTop\": true }");
+ ASSERT_TRUE(window);
+
+ // Disable always-on-top while in fullscreen mode.
+ window->Fullscreen();
+ EXPECT_FALSE(window->GetBaseWindow()->IsAlwaysOnTop());
+ window->SetAlwaysOnTop(false);
+ EXPECT_FALSE(window->GetBaseWindow()->IsAlwaysOnTop());
+
+ // Ensure that always-on-top remains disabled.
+ window->Restore();
+ EXPECT_FALSE(window->GetBaseWindow()->IsAlwaysOnTop());
+
+ CloseShellWindow(window);
+}
+
+} // namespace apps