Commit 03748e18 authored by Toshiki Kikuchi's avatar Toshiki Kikuchi Committed by Commit Bot

splitview: Avoid using animation disabled key to skip auto snapping

This CL allows AutoSnapController to check if
DragWindowFromShelfController is restoring windows after dragging.
AutoSnapController uses kAnimationsDisabledKey to skip auto snapping
after transient hide & show operations by DragWindowFromShelfController.
But kAnimationsDisabledKey may be used in other locations so we should
not rely on it.
This CL also cleans up auto snapping trigger conditions.

BUG=chromium:1107306
TEST=DragWindowFromShelfControllerTest.HideWindowDuringWindowDragging*
TEST=SplitViewControllerTest.AutoSnapFromMinimizedState

Change-Id: Ibc4f72558db3cf0efa070a77e44d3247b79d9ee7
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2303337
Commit-Queue: Toshiki Kikuchi <toshikikikuchi@chromium.org>
Reviewed-by: default avatarXiaoqian Dai <xdai@chromium.org>
Cr-Commit-Position: refs/heads/master@{#793002}
parent b77869ea
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include "ash/wm/splitview/split_view_controller.h" #include "ash/wm/splitview/split_view_controller.h"
#include "ash/wm/splitview/split_view_drag_indicators.h" #include "ash/wm/splitview/split_view_drag_indicators.h"
#include "ash/wm/splitview/split_view_utils.h" #include "ash/wm/splitview/split_view_utils.h"
#include "ash/wm/window_properties.h"
#include "ash/wm/window_state.h" #include "ash/wm/window_state.h"
#include "ash/wm/window_transient_descendant_iterator.h" #include "ash/wm/window_transient_descendant_iterator.h"
#include "ash/wm/window_util.h" #include "ash/wm/window_util.h"
...@@ -98,13 +99,16 @@ class DragWindowFromShelfController::WindowsHider ...@@ -98,13 +99,16 @@ class DragWindowFromShelfController::WindowsHider
hidden_windows_.push_back(window); hidden_windows_.push_back(window);
window->AddObserver(this); window->AddObserver(this);
window->SetProperty(kHideDuringWindowDragging, true);
} }
window_util::MinimizeAndHideWithoutAnimation(hidden_windows_); window_util::MinimizeAndHideWithoutAnimation(hidden_windows_);
} }
~WindowsHider() override { ~WindowsHider() override {
for (auto* window : hidden_windows_) for (auto* window : hidden_windows_) {
window->RemoveObserver(this); window->RemoveObserver(this);
window->ClearProperty(kHideDuringWindowDragging);
}
hidden_windows_.clear(); hidden_windows_.clear();
} }
...@@ -113,6 +117,7 @@ class DragWindowFromShelfController::WindowsHider ...@@ -113,6 +117,7 @@ class DragWindowFromShelfController::WindowsHider
window->RemoveObserver(this); window->RemoveObserver(this);
ScopedAnimationDisabler disabler(window); ScopedAnimationDisabler disabler(window);
window->Show(); window->Show();
window->ClearProperty(kHideDuringWindowDragging);
} }
hidden_windows_.clear(); hidden_windows_.clear();
} }
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include "ash/wm/splitview/split_view_constants.h" #include "ash/wm/splitview/split_view_constants.h"
#include "ash/wm/splitview/split_view_controller.h" #include "ash/wm/splitview/split_view_controller.h"
#include "ash/wm/tablet_mode/tablet_mode_controller_test_api.h" #include "ash/wm/tablet_mode/tablet_mode_controller_test_api.h"
#include "ash/wm/window_properties.h"
#include "ash/wm/window_state.h" #include "ash/wm/window_state.h"
#include "ash/wm/window_util.h" #include "ash/wm/window_util.h"
#include "base/test/metrics/histogram_tester.h" #include "base/test/metrics/histogram_tester.h"
...@@ -120,8 +121,10 @@ class DragWindowFromShelfControllerTest : public AshTestBase { ...@@ -120,8 +121,10 @@ class DragWindowFromShelfControllerTest : public AshTestBase {
DISALLOW_COPY_AND_ASSIGN(DragWindowFromShelfControllerTest); DISALLOW_COPY_AND_ASSIGN(DragWindowFromShelfControllerTest);
}; };
// Tests that we may hide different sets of windows in different scenarios. // Tests that we may hide different sets of windows with a special flag
TEST_F(DragWindowFromShelfControllerTest, HideWindowDuringWindowDragging) { // kHideDuringWindowDragging.
TEST_F(DragWindowFromShelfControllerTest,
HideWindowDuringWindowDraggingWithFlag) {
UpdateDisplay("400x400"); UpdateDisplay("400x400");
const gfx::Rect shelf_bounds = const gfx::Rect shelf_bounds =
Shelf::ForWindow(Shell::GetPrimaryRootWindow())->GetIdealBounds(); Shelf::ForWindow(Shell::GetPrimaryRootWindow())->GetIdealBounds();
...@@ -132,21 +135,48 @@ TEST_F(DragWindowFromShelfControllerTest, HideWindowDuringWindowDragging) { ...@@ -132,21 +135,48 @@ TEST_F(DragWindowFromShelfControllerTest, HideWindowDuringWindowDragging) {
EXPECT_TRUE(window1->IsVisible()); EXPECT_TRUE(window1->IsVisible());
EXPECT_TRUE(window2->IsVisible()); EXPECT_TRUE(window2->IsVisible());
EXPECT_TRUE(window3->IsVisible()); EXPECT_TRUE(window3->IsVisible());
EXPECT_FALSE(window1->GetProperty(kHideDuringWindowDragging));
EXPECT_FALSE(window2->GetProperty(kHideDuringWindowDragging));
EXPECT_FALSE(window3->GetProperty(kHideDuringWindowDragging));
StartDrag(window1.get(), shelf_bounds.CenterPoint(), HotseatState::kExtended); StartDrag(window1.get(), shelf_bounds.CenterPoint(), HotseatState::kExtended);
Drag(gfx::Point(200, 200), 1.f, 1.f); Drag(gfx::Point(200, 200), 1.f, 1.f);
EXPECT_TRUE(window1->IsVisible()); EXPECT_TRUE(window1->IsVisible());
EXPECT_FALSE(window2->IsVisible()); EXPECT_FALSE(window2->IsVisible());
EXPECT_FALSE(window3->IsVisible()); EXPECT_FALSE(window3->IsVisible());
EXPECT_FALSE(window1->GetProperty(kHideDuringWindowDragging));
EXPECT_TRUE(window2->GetProperty(kHideDuringWindowDragging));
EXPECT_TRUE(window3->GetProperty(kHideDuringWindowDragging));
EndDrag(shelf_bounds.CenterPoint(), /*velocity_y=*/base::nullopt); EndDrag(shelf_bounds.CenterPoint(), /*velocity_y=*/base::nullopt);
EXPECT_TRUE(window1->IsVisible()); EXPECT_TRUE(window1->IsVisible());
EXPECT_TRUE(window2->IsVisible()); EXPECT_TRUE(window2->IsVisible());
EXPECT_TRUE(window3->IsVisible()); EXPECT_TRUE(window3->IsVisible());
EXPECT_FALSE(window1->GetProperty(kHideDuringWindowDragging));
EXPECT_FALSE(window2->GetProperty(kHideDuringWindowDragging));
EXPECT_FALSE(window3->GetProperty(kHideDuringWindowDragging));
}
// Tests that we may hide different sets of windows in splitview and restores
// windows correctly after dragging.
TEST_F(DragWindowFromShelfControllerTest,
HideWindowDuringWindowDraggingInSplitView) {
UpdateDisplay("400x400");
const gfx::Rect shelf_bounds =
Shelf::ForWindow(Shell::GetPrimaryRootWindow())->GetIdealBounds();
auto window3 = CreateTestWindow();
auto window2 = CreateTestWindow();
auto window1 = CreateTestWindow();
EXPECT_TRUE(window1->IsVisible());
EXPECT_TRUE(window2->IsVisible());
EXPECT_TRUE(window3->IsVisible());
// In splitview mode, the snapped windows will stay visible during dragging. // In splitview mode, the snapped windows will stay visible during dragging.
split_view_controller()->SnapWindow(window1.get(), SplitViewController::LEFT); split_view_controller()->SnapWindow(window1.get(), SplitViewController::LEFT);
split_view_controller()->SnapWindow(window2.get(), split_view_controller()->SnapWindow(window2.get(),
SplitViewController::RIGHT); SplitViewController::RIGHT);
// Try to drag a left snapped window
StartDrag(window1.get(), shelf_bounds.left_center(), HotseatState::kExtended); StartDrag(window1.get(), shelf_bounds.left_center(), HotseatState::kExtended);
Drag(gfx::Point(0, 200), 1.f, 1.f); Drag(gfx::Point(0, 200), 1.f, 1.f);
EXPECT_TRUE(window1->IsVisible()); EXPECT_TRUE(window1->IsVisible());
...@@ -156,7 +186,17 @@ TEST_F(DragWindowFromShelfControllerTest, HideWindowDuringWindowDragging) { ...@@ -156,7 +186,17 @@ TEST_F(DragWindowFromShelfControllerTest, HideWindowDuringWindowDragging) {
EXPECT_TRUE(window1->IsVisible()); EXPECT_TRUE(window1->IsVisible());
EXPECT_TRUE(window2->IsVisible()); EXPECT_TRUE(window2->IsVisible());
EXPECT_TRUE(window3->IsVisible()); EXPECT_TRUE(window3->IsVisible());
// Ensure that all windows are restored correctly without triggering auto
// snapping.
EXPECT_TRUE(split_view_controller()->IsWindowInSplitView(window1.get()));
EXPECT_EQ(split_view_controller()->GetPositionOfSnappedWindow(window1.get()),
SplitViewController::LEFT);
EXPECT_TRUE(split_view_controller()->IsWindowInSplitView(window2.get()));
EXPECT_EQ(split_view_controller()->GetPositionOfSnappedWindow(window2.get()),
SplitViewController::RIGHT);
EXPECT_FALSE(split_view_controller()->IsWindowInSplitView(window3.get()));
// Try to drag a right snapped window
StartDrag(window2.get(), shelf_bounds.right_center(), StartDrag(window2.get(), shelf_bounds.right_center(),
HotseatState::kExtended); HotseatState::kExtended);
Drag(gfx::Point(400, 200), 1.f, 1.f); Drag(gfx::Point(400, 200), 1.f, 1.f);
...@@ -167,6 +207,15 @@ TEST_F(DragWindowFromShelfControllerTest, HideWindowDuringWindowDragging) { ...@@ -167,6 +207,15 @@ TEST_F(DragWindowFromShelfControllerTest, HideWindowDuringWindowDragging) {
EXPECT_TRUE(window1->IsVisible()); EXPECT_TRUE(window1->IsVisible());
EXPECT_TRUE(window2->IsVisible()); EXPECT_TRUE(window2->IsVisible());
EXPECT_TRUE(window3->IsVisible()); EXPECT_TRUE(window3->IsVisible());
// Ensure that all windows are restored correctly without triggering auto
// snapping.
EXPECT_TRUE(split_view_controller()->IsWindowInSplitView(window1.get()));
EXPECT_EQ(split_view_controller()->GetPositionOfSnappedWindow(window1.get()),
SplitViewController::LEFT);
EXPECT_TRUE(split_view_controller()->IsWindowInSplitView(window2.get()));
EXPECT_EQ(split_view_controller()->GetPositionOfSnappedWindow(window2.get()),
SplitViewController::RIGHT);
EXPECT_FALSE(split_view_controller()->IsWindowInSplitView(window3.get()));
} }
// Test home launcher is hidden during dragging. // Test home launcher is hidden during dragging.
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include "ash/wm/splitview/split_view_utils.h" #include "ash/wm/splitview/split_view_utils.h"
#include "ash/wm/tablet_mode/tablet_mode_controller.h" #include "ash/wm/tablet_mode/tablet_mode_controller.h"
#include "ash/wm/tablet_mode/tablet_mode_window_state.h" #include "ash/wm/tablet_mode/tablet_mode_window_state.h"
#include "ash/wm/window_properties.h"
#include "ash/wm/window_resizer.h" #include "ash/wm/window_resizer.h"
#include "ash/wm/window_state.h" #include "ash/wm/window_state.h"
#include "ash/wm/window_transient_descendant_iterator.h" #include "ash/wm/window_transient_descendant_iterator.h"
...@@ -405,22 +406,29 @@ class SplitViewController::AutoSnapController ...@@ -405,22 +406,29 @@ class SplitViewController::AutoSnapController
// aura::WindowObserver: // aura::WindowObserver:
void OnWindowVisibilityChanging(aura::Window* window, bool visible) override { void OnWindowVisibilityChanging(aura::Window* window, bool visible) override {
// TODO(toshikikikuchi): Consider avoiding to use kAnimationsDisabledKey // When a minimized window's visibility changes from invisible to visible or
// here just for |DragWindowFromShelfController|. // is about to activate, it triggers an implicit un-minimizing (e.g.
if (visible && WindowState::Get(window) && // |WorkspaceLayoutManager::OnChildWindowVisibilityChanged| or
WindowState::Get(window)->IsMinimized() && // |WorkspaceLayoutManager::OnWindowActivating|). This emits a window
!window->GetProperty(aura::client::kAnimationsDisabledKey)) { // state change event but it is unnecessary for to-be-snapped windows
// A visible but minimized window state triggers an implicit un-minimizing // because some clients (e.g. ARC app) handle a window state change
// by someone (e.g. // asynchronously. So in the case, we here try to snap a window before
// |WorkspaceLayoutManager::OnChildWindowVisibilityChanged| or // other's handling to avoid the implicit un-minimizing.
// |WorkspaceLayoutManager::OnWindowActivating|). This emits a window
// state change event but it is unnecessary for to-be-snapped windows // Auto snapping is applicable for window changed to be visible.
// because some clients (e.g. ARC app) handle a window state change if (!visible)
// asynchronously. So in the case, we here try to snap a window before return;
// other's handling. Animation-disabled visibility changes are used for
// transient hide & show operations so not applicable for auto snapping. // Already un-minimized windows are not applicable for auto snapping.
AutoSnapWindowIfNeeded(window); if (!WindowState::Get(window) || !WindowState::Get(window)->IsMinimized())
} return;
// Visibility changes while restoring windows after dragged is transient
// hide & show operations so not applicable for auto snapping.
if (window->GetProperty(kHideDuringWindowDragging))
return;
AutoSnapWindowIfNeeded(window);
} }
void OnWindowAddedToRootWindow(aura::Window* window) override { void OnWindowAddedToRootWindow(aura::Window* window) override {
......
...@@ -47,6 +47,7 @@ ...@@ -47,6 +47,7 @@
#include "ash/wm/tablet_mode/tablet_mode_controller.h" #include "ash/wm/tablet_mode/tablet_mode_controller.h"
#include "ash/wm/tablet_mode/tablet_mode_window_drag_delegate.h" #include "ash/wm/tablet_mode/tablet_mode_window_drag_delegate.h"
#include "ash/wm/tablet_mode/tablet_mode_window_resizer.h" #include "ash/wm/tablet_mode/tablet_mode_window_resizer.h"
#include "ash/wm/window_properties.h"
#include "ash/wm/window_resizer.h" #include "ash/wm/window_resizer.h"
#include "ash/wm/window_state.h" #include "ash/wm/window_state.h"
#include "ash/wm/window_state_delegate.h" #include "ash/wm/window_state_delegate.h"
...@@ -2735,6 +2736,21 @@ TEST_P(SplitViewControllerTest, AutoSnapFromMinimizedState) { ...@@ -2735,6 +2736,21 @@ TEST_P(SplitViewControllerTest, AutoSnapFromMinimizedState) {
EXPECT_FALSE(split_view_controller()->InSplitViewMode()); EXPECT_FALSE(split_view_controller()->InSplitViewMode());
EXPECT_FALSE(split_view_controller()->IsWindowInSplitView(window2.get())); EXPECT_FALSE(split_view_controller()->IsWindowInSplitView(window2.get()));
// Nothing should happen for transient visibility changing due to dragging.
Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
split_view_controller()->SnapWindow(window3.get(), SplitViewController::LEFT);
EXPECT_TRUE(split_view_controller()->InTabletSplitViewMode());
EXPECT_TRUE(split_view_controller()->IsWindowInSplitView(window3.get()));
EXPECT_EQ(split_view_controller()->GetPositionOfSnappedWindow(window3.get()),
SplitViewController::LEFT);
WindowState::Get(window1.get())->Minimize();
window1->SetProperty(kHideDuringWindowDragging, true);
window1->Show();
EXPECT_FALSE(split_view_controller()->IsWindowInSplitView(window1.get()));
window1->ClearProperty(kHideDuringWindowDragging);
// Should performs auto snapping when showing a snappable window in table // Should performs auto snapping when showing a snappable window in table
// split view mode. // split view mode.
Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true); Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
......
...@@ -11,6 +11,8 @@ DEFINE_EXPORTED_UI_CLASS_PROPERTY_TYPE(ASH_EXPORT, ash::WindowState*) ...@@ -11,6 +11,8 @@ DEFINE_EXPORTED_UI_CLASS_PROPERTY_TYPE(ASH_EXPORT, ash::WindowState*)
namespace ash { namespace ash {
DEFINE_UI_CLASS_PROPERTY_KEY(bool, kHideDuringWindowDragging, false)
DEFINE_UI_CLASS_PROPERTY_KEY(bool, kLockedToRootKey, false) DEFINE_UI_CLASS_PROPERTY_KEY(bool, kLockedToRootKey, false)
DEFINE_UI_CLASS_PROPERTY_KEY(bool, kWindowIsJanky, false) DEFINE_UI_CLASS_PROPERTY_KEY(bool, kWindowIsJanky, false)
......
...@@ -22,6 +22,11 @@ class WindowState; ...@@ -22,6 +22,11 @@ class WindowState;
// Alphabetical sort. // Alphabetical sort.
// A property key to indicate whether this window is temporarily hidden because
// of the window dragging.
ASH_EXPORT extern const aura::WindowProperty<bool>* const
kHideDuringWindowDragging;
// If this is set to true, the window stays in the same root window even if the // If this is set to true, the window stays in the same root window even if the
// bounds outside of its root window is set. // bounds outside of its root window is set.
ASH_EXPORT extern const aura::WindowProperty<bool>* const kLockedToRootKey; ASH_EXPORT extern const aura::WindowProperty<bool>* const kLockedToRootKey;
......
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