Commit 5e39e65d authored by Joel Hockey's avatar Joel Hockey Committed by Chromium LUCI CQ

Always hide shelf for Parallels in fullscreen, allow esc to restore

Adds window properties for
 * kEscHoldToExitFullscreen - if true holding esc for 2s will exit
   fullscreen.
 * kEscHoldExitFullscreenToMinimized - if true window is minimized
   when it exits from fullscreen rather than being restored to normal.

AppServiceAppWindowLauncherController sets these properties on:
 * Borealis to use esc, and minimize on exit
 * PluginVM to use esc, and restore on exit

Bug: 1144780
Change-Id: Ibcbbb811f99b5650df6b16e0de85b2b5129a4a30
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2581626Reviewed-by: default avatarMitsuru Oshima <oshima@chromium.org>
Commit-Queue: Joel Hockey <joelhockey@chromium.org>
Cr-Commit-Position: refs/heads/master@{#836060}
parent a6dd1742
......@@ -36,9 +36,11 @@
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/grit/chrome_unscaled_resources.h"
#include "chromeos/ui/base/window_properties.h"
#include "components/account_id/account_id.h"
#include "components/arc/arc_util.h"
#include "components/exo/shell_surface_base.h"
#include "components/exo/shell_surface_util.h"
#include "components/services/app_service/public/cpp/instance.h"
#include "components/services/app_service/public/mojom/types.mojom-shared.h"
#include "components/services/app_service/public/mojom/types.mojom.h"
......@@ -505,30 +507,35 @@ void AppServiceAppWindowLauncherController::RegisterWindow(
// so we don't need to call AddWindowToShelf again.
if (arc_tracker_ && arc::GetWindowTaskId(window) != arc::kNoTaskId) {
arc_tracker_->AttachControllerToWindow(window);
} else {
// The window for ARC Play Store is a special window, which is created by
// both Extensions and ARC. If Extensions's window is generated after
// ARC window, calls OnItemDelegateDiscarded to remove the ARC apps
// window.
if (shelf_id.app_id == arc::kPlayStoreAppId) {
AppWindowLauncherItemController* item_controller =
owner()->shelf_model()->GetAppWindowLauncherItemController(shelf_id);
if (item_controller && shelf_id.app_id == arc::kPlayStoreAppId &&
arc_tracker_) {
OnItemDelegateDiscarded(item_controller);
}
}
AddWindowToShelf(window, shelf_id);
return;
}
if (plugin_vm::IsPluginVmAppWindow(window)) {
// Set an icon for the Plugin VM app window.
static_cast<exo::ShellSurfaceBase*>(
views::Widget::GetWidgetForNativeWindow(window)->widget_delegate())
->SetIcon(*ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
IDR_LOGO_PLUGIN_VM_DEFAULT_192));
// The window for ARC Play Store is a special window, which is created by
// both Extensions and ARC. If Extensions's window is generated after
// ARC window, calls OnItemDelegateDiscarded to remove the ARC apps
// window.
if (shelf_id.app_id == arc::kPlayStoreAppId) {
AppWindowLauncherItemController* item_controller =
owner()->shelf_model()->GetAppWindowLauncherItemController(shelf_id);
if (item_controller && shelf_id.app_id == arc::kPlayStoreAppId &&
arc_tracker_) {
OnItemDelegateDiscarded(item_controller);
}
} else if (plugin_vm::IsPluginVmAppWindow(window)) {
// Set an icon for the Plugin VM app window, and set fullscreen properties.
static_cast<exo::ShellSurfaceBase*>(
views::Widget::GetWidgetForNativeWindow(window)->widget_delegate())
->SetIcon(*ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
IDR_LOGO_PLUGIN_VM_DEFAULT_192));
exo::SetShellUseImmersiveForFullscreen(window, false);
window->SetProperty(chromeos::kEscHoldToExitFullscreen, true);
} else if (borealis::BorealisWindowManager::IsBorealisWindow(window)) {
// Set fullscreen properties for Borealis.
window->SetProperty(chromeos::kEscHoldToExitFullscreen, true);
window->SetProperty(chromeos::kEscHoldExitFullscreenToMinimized, true);
}
AddWindowToShelf(window, shelf_id);
}
void AppServiceAppWindowLauncherController::UnregisterAppWindow(
......
......@@ -19,6 +19,9 @@ namespace chromeos {
DEFINE_UI_CLASS_PROPERTY_KEY(bool, kBlockedForAssistantSnapshotKey, false)
DEFINE_UI_CLASS_PROPERTY_KEY(bool, kEscHoldToExitFullscreen, false)
DEFINE_UI_CLASS_PROPERTY_KEY(bool, kEscHoldExitFullscreenToMinimized, false)
DEFINE_UI_CLASS_PROPERTY_KEY(SkColor, kFrameActiveColorKey, kDefaultFrameColor)
DEFINE_UI_CLASS_PROPERTY_KEY(SkColor,
kFrameInactiveColorKey,
......
......@@ -28,6 +28,15 @@ enum class WindowPinType;
COMPONENT_EXPORT(CHROMEOS_UI_BASE)
extern const ui::ClassProperty<bool>* const kBlockedForAssistantSnapshotKey;
// Whether holding esc should exit fullscreen. Used by Borealis and Plugin VM.
COMPONENT_EXPORT(CHROMEOS_UI_BASE)
extern const ui::ClassProperty<bool>* const kEscHoldToExitFullscreen;
// Whether screen should minimize when using esc hold to exit fullscreen.
// Borealis apps set this since they do not handle window size changes.
COMPONENT_EXPORT(CHROMEOS_UI_BASE)
extern const ui::ClassProperty<bool>* const kEscHoldExitFullscreenToMinimized;
// A property key to store the active color on the window frame.
COMPONENT_EXPORT(CHROMEOS_UI_BASE)
extern const ui::ClassProperty<SkColor>* const kFrameActiveColorKey;
......
......@@ -56,7 +56,7 @@ void UILockController::OnSurfaceFocused(Surface* gained_focus) {
}
namespace {
bool FocusedWindowIsNonImmersiveFullscreen(Seat* seat) {
bool EscapeHoldShouldExitFullscreen(Seat* seat) {
auto* surface = seat->GetFocusedSurface();
if (!surface)
return false;
......@@ -67,12 +67,7 @@ bool FocusedWindowIsNonImmersiveFullscreen(Seat* seat) {
return false;
aura::Window* window = widget->GetNativeWindow();
if (!window || window->GetProperty(chromeos::kImmersiveImpliedByFullscreen))
return false;
// TODO(b/165865831): Add the Borealis AppType if/when we add one.
if (window->GetProperty(aura::client::kAppType) !=
static_cast<int>(ash::AppType::CROSTINI_APP)) {
if (!window || !window->GetProperty(chromeos::kEscHoldToExitFullscreen)) {
return false;
}
......@@ -83,7 +78,7 @@ bool FocusedWindowIsNonImmersiveFullscreen(Seat* seat) {
void UILockController::OnEscapeKey(bool pressed) {
if (pressed) {
if (FocusedWindowIsNonImmersiveFullscreen(seat_) &&
if (EscapeHoldShouldExitFullscreen(seat_) &&
!exit_fullscreen_timer_.IsRunning()) {
focused_surface_to_unlock_ = seat_->GetFocusedSurface();
exit_fullscreen_timer_.Start(
......@@ -109,8 +104,14 @@ void UILockController::OnEscapeHeld() {
views::Widget::GetTopLevelWidgetForNativeView(surface->window());
auto* window_state =
ash::WindowState::Get(widget ? widget->GetNativeWindow() : nullptr);
if (window_state)
window_state->Minimize();
if (window_state) {
if (window_state->window()->GetProperty(
chromeos::kEscHoldExitFullscreenToMinimized)) {
window_state->Minimize();
} else {
window_state->Restore();
}
}
}
void UILockController::StopTimer() {
......
......@@ -4,9 +4,9 @@
#include "components/exo/ui_lock_controller.h"
#include "ash/public/cpp/app_types.h"
#include "ash/shell.h"
#include "ash/wm/window_state.h"
#include "chromeos/ui/base/window_properties.h"
#include "components/exo/buffer.h"
#include "components/exo/display.h"
#include "components/exo/shell_surface.h"
......@@ -14,7 +14,6 @@
#include "components/exo/test/exo_test_base.h"
#include "components/exo/test/exo_test_helper.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/wm/core/window_util.h"
namespace exo {
......@@ -74,17 +73,13 @@ class UILockControllerTest : public test::ExoTestBase {
std::unique_ptr<Seat> seat_;
};
void SetAppType(SurfaceTriplet& surface, ash::AppType appType) {
surface.GetTopLevelWindow()->SetProperty(aura::client::kAppType,
static_cast<int>(appType));
}
TEST_F(UILockControllerTest, HoldingEscapeExitsFullscreen) {
SurfaceTriplet test_surface = BuildSurface(1024, 768);
test_surface.shell_surface->SetUseImmersiveForFullscreen(false);
test_surface.shell_surface->SetFullscreen(true);
test_surface.surface->Commit();
SetAppType(test_surface, ash::AppType::CROSTINI_APP);
test_surface.GetTopLevelWindow()->SetProperty(
chromeos::kEscHoldToExitFullscreen, true);
auto* window_state = test_surface.GetTopLevelWindowState();
EXPECT_TRUE(window_state->IsFullscreen());
......@@ -94,6 +89,7 @@ TEST_F(UILockControllerTest, HoldingEscapeExitsFullscreen) {
task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(1));
EXPECT_FALSE(window_state->IsFullscreen());
EXPECT_TRUE(window_state->IsNormalStateType());
}
TEST_F(UILockControllerTest, HoldingCtrlEscapeDoesNotExitFullscreen) {
......@@ -101,7 +97,8 @@ TEST_F(UILockControllerTest, HoldingCtrlEscapeDoesNotExitFullscreen) {
test_surface.shell_surface->SetUseImmersiveForFullscreen(false);
test_surface.shell_surface->SetFullscreen(true);
test_surface.surface->Commit();
SetAppType(test_surface, ash::AppType::CROSTINI_APP);
test_surface.GetTopLevelWindow()->SetProperty(
chromeos::kEscHoldToExitFullscreen, true);
auto* window_state = test_surface.GetTopLevelWindowState();
EXPECT_TRUE(window_state->IsFullscreen());
......@@ -110,12 +107,13 @@ TEST_F(UILockControllerTest, HoldingCtrlEscapeDoesNotExitFullscreen) {
EXPECT_TRUE(window_state->IsFullscreen());
}
TEST_F(UILockControllerTest, HoldingEscapeOnlyAffectsCrostiniApps) {
TEST_F(UILockControllerTest,
HoldingEscapeOnlyExitsFullscreenIfWindowPropertySet) {
SurfaceTriplet test_surface = BuildSurface(1024, 768);
test_surface.shell_surface->SetUseImmersiveForFullscreen(false);
test_surface.shell_surface->SetFullscreen(true);
test_surface.surface->Commit();
SetAppType(test_surface, ash::AppType::ARC_APP);
// Do not set chromeos::kEscHoldToExitFullscreen on TopLevelWindow.
auto* window_state = test_surface.GetTopLevelWindowState();
EXPECT_TRUE(window_state->IsFullscreen());
......@@ -129,13 +127,15 @@ TEST_F(UILockControllerTest, HoldingEscapeOnlyExitsFocusedFullscreen) {
test_surface1.shell_surface->SetUseImmersiveForFullscreen(false);
test_surface1.shell_surface->SetFullscreen(true);
test_surface1.surface->Commit();
SetAppType(test_surface1, ash::AppType::CROSTINI_APP);
test_surface1.GetTopLevelWindow()->SetProperty(
chromeos::kEscHoldToExitFullscreen, true);
SurfaceTriplet test_surface2 = BuildSurface(1024, 768);
test_surface2.shell_surface->SetUseImmersiveForFullscreen(false);
test_surface2.shell_surface->SetFullscreen(true);
test_surface2.surface->Commit();
SetAppType(test_surface2, ash::AppType::CROSTINI_APP);
test_surface2.GetTopLevelWindow()->SetProperty(
chromeos::kEscHoldToExitFullscreen, true);
GetEventGenerator()->PressKey(ui::VKEY_ESCAPE, ui::EF_NONE);
task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(2));
......@@ -150,7 +150,8 @@ TEST_F(UILockControllerTest, DestroyingWindowCancels) {
test_surface->shell_surface->SetUseImmersiveForFullscreen(false);
test_surface->shell_surface->SetFullscreen(true);
test_surface->surface->Commit();
SetAppType(*test_surface, ash::AppType::CROSTINI_APP);
test_surface->GetTopLevelWindow()->SetProperty(
chromeos::kEscHoldToExitFullscreen, true);
auto* window_state = test_surface->GetTopLevelWindowState();
EXPECT_TRUE(window_state->IsFullscreen());
......@@ -168,13 +169,13 @@ TEST_F(UILockControllerTest, FocusChangeCancels) {
// Arrange: two windows, one is fullscreen and focused
SurfaceTriplet other_surface = BuildSurface(1024, 768);
other_surface.surface->Commit();
SetAppType(other_surface, ash::AppType::CROSTINI_APP);
SurfaceTriplet fullscreen_surface = BuildSurface(1024, 768);
fullscreen_surface.shell_surface->SetUseImmersiveForFullscreen(false);
fullscreen_surface.shell_surface->SetFullscreen(true);
fullscreen_surface.surface->Commit();
SetAppType(fullscreen_surface, ash::AppType::CROSTINI_APP);
fullscreen_surface.GetTopLevelWindow()->SetProperty(
chromeos::kEscHoldToExitFullscreen, true);
EXPECT_EQ(fullscreen_surface.surface.get(), seat_->GetFocusedSurface());
EXPECT_FALSE(fullscreen_surface.GetTopLevelWindowState()->IsMinimized());
......@@ -193,41 +194,53 @@ TEST_F(UILockControllerTest, FocusChangeCancels) {
EXPECT_EQ(fullscreen_surface.surface.get(), seat_->GetFocusedSurface());
}
TEST_F(UILockControllerTest, EscapeDoesNotExitImmersiveFullscreen) {
TEST_F(UILockControllerTest, ShortHoldEscapeDoesNotExitFullscreen) {
SurfaceTriplet test_surface = BuildSurface(1024, 768);
test_surface.shell_surface->SetUseImmersiveForFullscreen(false);
test_surface.shell_surface->SetFullscreen(true);
test_surface.surface->Commit();
SetAppType(test_surface, ash::AppType::CROSTINI_APP);
test_surface.GetTopLevelWindow()->SetProperty(
chromeos::kEscHoldToExitFullscreen, true);
auto* window_state = test_surface.GetTopLevelWindowState();
GetEventGenerator()->PressKey(ui::VKEY_ESCAPE, ui::EF_NONE);
task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(1));
GetEventGenerator()->ReleaseKey(ui::VKEY_ESCAPE, ui::EF_NONE);
task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(2));
EXPECT_TRUE(window_state->IsFullscreen());
}
TEST_F(UILockControllerTest, ShortHoldEscapeDoesNotExitFullscreen) {
TEST_F(UILockControllerTest, HoldingEscapeMinimizesIfPropertySet) {
SurfaceTriplet test_surface = BuildSurface(1024, 768);
test_surface.shell_surface->SetUseImmersiveForFullscreen(false);
test_surface.shell_surface->SetFullscreen(true);
test_surface.surface->Commit();
SetAppType(test_surface, ash::AppType::CROSTINI_APP);
test_surface.GetTopLevelWindow()->SetProperty(
chromeos::kEscHoldToExitFullscreen, true);
test_surface.GetTopLevelWindow()->SetProperty(
chromeos::kEscHoldExitFullscreenToMinimized, true);
auto* window_state = test_surface.GetTopLevelWindowState();
EXPECT_TRUE(window_state->IsFullscreen());
GetEventGenerator()->PressKey(ui::VKEY_ESCAPE, ui::EF_NONE);
task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(1));
GetEventGenerator()->ReleaseKey(ui::VKEY_ESCAPE, ui::EF_NONE);
task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(2));
EXPECT_TRUE(window_state->IsFullscreen()); // no change yet
EXPECT_TRUE(window_state->IsFullscreen());
task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(1));
EXPECT_FALSE(window_state->IsFullscreen());
EXPECT_TRUE(window_state->IsMinimized());
}
TEST_F(UILockControllerTest, HoldingEscapeDoesNotMinimizeIfWindowed) {
SurfaceTriplet test_surface = BuildSurface(1024, 768);
test_surface.shell_surface->SetUseImmersiveForFullscreen(false);
test_surface.surface->Commit();
SetAppType(test_surface, ash::AppType::CROSTINI_APP);
auto* window_state = test_surface.GetTopLevelWindowState();
test_surface.GetTopLevelWindow()->SetProperty(
chromeos::kEscHoldToExitFullscreen, true);
test_surface.GetTopLevelWindow()->SetProperty(
chromeos::kEscHoldExitFullscreenToMinimized, true);
GetEventGenerator()->PressKey(ui::VKEY_ESCAPE, ui::EF_NONE);
task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(2));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment