1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "ash/wm/overview/overview_session.h"
6
7 #include <algorithm>
8 #include <memory>
9 #include <string>
10 #include <utility>
11 #include <vector>
12
13 #include "ash/accelerators/accelerator_controller_impl.h"
14 #include "ash/accelerators/exit_warning_handler.h"
15 #include "ash/accessibility/accessibility_controller_impl.h"
16 #include "ash/accessibility/test_accessibility_controller_client.h"
17 #include "ash/app_list/app_list_controller_impl.h"
18 #include "ash/display/screen_orientation_controller.h"
19 #include "ash/display/screen_orientation_controller_test_api.h"
20 #include "ash/drag_drop/drag_drop_controller.h"
21 #include "ash/home_screen/home_screen_controller.h"
22 #include "ash/magnifier/docked_magnifier_controller_impl.h"
23 #include "ash/public/cpp/app_types.h"
24 #include "ash/public/cpp/ash_features.h"
25 #include "ash/public/cpp/shelf_config.h"
26 #include "ash/public/cpp/test/shell_test_api.h"
27 #include "ash/public/cpp/window_properties.h"
28 #include "ash/screen_util.h"
29 #include "ash/shelf/shelf.h"
30 #include "ash/shelf/shelf_view_test_api.h"
31 #include "ash/shell.h"
32 #include "ash/test/ash_test_base.h"
33 #include "ash/wm/desks/desks_util.h"
34 #include "ash/wm/drag_window_resizer.h"
35 #include "ash/wm/gestures/back_gesture/back_gesture_event_handler.h"
36 #include "ash/wm/mru_window_tracker.h"
37 #include "ash/wm/overview/overview_constants.h"
38 #include "ash/wm/overview/overview_controller.h"
39 #include "ash/wm/overview/overview_grid.h"
40 #include "ash/wm/overview/overview_grid_event_handler.h"
41 #include "ash/wm/overview/overview_highlight_controller.h"
42 #include "ash/wm/overview/overview_item.h"
43 #include "ash/wm/overview/overview_item_view.h"
44 #include "ash/wm/overview/overview_test_util.h"
45 #include "ash/wm/overview/overview_utils.h"
46 #include "ash/wm/overview/overview_wallpaper_controller.h"
47 #include "ash/wm/overview/overview_window_drag_controller.h"
48 #include "ash/wm/overview/rounded_label_widget.h"
49 #include "ash/wm/overview/scoped_overview_transform_window.h"
50 #include "ash/wm/resize_shadow.h"
51 #include "ash/wm/resize_shadow_controller.h"
52 #include "ash/wm/splitview/multi_display_overview_and_split_view_test.h"
53 #include "ash/wm/splitview/split_view_controller.h"
54 #include "ash/wm/splitview/split_view_divider.h"
55 #include "ash/wm/splitview/split_view_drag_indicators.h"
56 #include "ash/wm/splitview/split_view_utils.h"
57 #include "ash/wm/tablet_mode/tablet_mode_browser_window_drag_delegate.h"
58 #include "ash/wm/tablet_mode/tablet_mode_controller.h"
59 #include "ash/wm/tablet_mode/tablet_mode_controller_test_api.h"
60 #include "ash/wm/tablet_mode/tablet_mode_window_resizer.h"
61 #include "ash/wm/window_preview_view.h"
62 #include "ash/wm/window_state.h"
63 #include "ash/wm/window_state_delegate.h"
64 #include "ash/wm/window_util.h"
65 #include "ash/wm/wm_event.h"
66 #include "ash/wm/workspace/workspace_window_resizer.h"
67 #include "base/macros.h"
68 #include "base/memory/ptr_util.h"
69 #include "base/run_loop.h"
70 #include "base/stl_util.h"
71 #include "base/strings/utf_string_conversions.h"
72 #include "base/test/metrics/histogram_tester.h"
73 #include "base/test/metrics/user_action_tester.h"
74 #include "base/test/scoped_feature_list.h"
75 #include "base/time/time.h"
76 #include "ui/aura/client/aura_constants.h"
77 #include "ui/aura/client/window_types.h"
78 #include "ui/aura/test/test_window_delegate.h"
79 #include "ui/aura/window.h"
80 #include "ui/aura/window_event_dispatcher.h"
81 #include "ui/aura/window_tree_host.h"
82 #include "ui/base/hit_test.h"
83 #include "ui/compositor/layer_animation_sequence.h"
84 #include "ui/compositor/scoped_animation_duration_scale_mode.h"
85 #include "ui/compositor/test/draw_waiter_for_test.h"
86 #include "ui/compositor/test/test_utils.h"
87 #include "ui/display/display_layout.h"
88 #include "ui/display/manager/display_manager.h"
89 #include "ui/display/test/display_manager_test_api.h"
90 #include "ui/events/event_utils.h"
91 #include "ui/events/gesture_detection/gesture_configuration.h"
92 #include "ui/events/test/event_generator.h"
93 #include "ui/gfx/geometry/point_conversions.h"
94 #include "ui/gfx/transform.h"
95 #include "ui/gfx/transform_util.h"
96 #include "ui/views/accessibility/view_accessibility.h"
97 #include "ui/views/controls/button/image_button.h"
98 #include "ui/views/controls/label.h"
99 #include "ui/views/widget/widget.h"
100 #include "ui/wm/core/coordinate_conversion.h"
101 #include "ui/wm/core/cursor_manager.h"
102 #include "ui/wm/core/shadow_controller.h"
103 #include "ui/wm/core/window_util.h"
104
105 namespace ash {
106 namespace {
107
108 using ::chromeos::WindowStateType;
109
110 constexpr const char kActiveWindowChangedFromOverview[] =
111 "WindowSelector_ActiveWindowChanged";
112
113 // Helper function to get the index of |child|, given its parent window
114 // |parent|.
IndexOf(aura::Window * child,aura::Window * parent)115 int IndexOf(aura::Window* child, aura::Window* parent) {
116 aura::Window::Windows children = parent->children();
117 auto it = std::find(children.begin(), children.end(), child);
118 DCHECK(it != children.end());
119
120 return static_cast<int>(std::distance(children.begin(), it));
121 }
122
123 class TweenTester : public ui::LayerAnimationObserver {
124 public:
TweenTester(aura::Window * window)125 explicit TweenTester(aura::Window* window) : window_(window) {
126 window->layer()->GetAnimator()->AddObserver(this);
127 }
128
~TweenTester()129 ~TweenTester() override {
130 window_->layer()->GetAnimator()->RemoveObserver(this);
131 EXPECT_TRUE(will_animate_);
132 }
133
134 // ui::LayerAnimationObserver:
OnLayerAnimationEnded(ui::LayerAnimationSequence * sequence)135 void OnLayerAnimationEnded(ui::LayerAnimationSequence* sequence) override {}
OnLayerAnimationAborted(ui::LayerAnimationSequence * sequence)136 void OnLayerAnimationAborted(ui::LayerAnimationSequence* sequence) override {}
OnLayerAnimationScheduled(ui::LayerAnimationSequence * sequence)137 void OnLayerAnimationScheduled(
138 ui::LayerAnimationSequence* sequence) override {}
OnAttachedToSequence(ui::LayerAnimationSequence * sequence)139 void OnAttachedToSequence(ui::LayerAnimationSequence* sequence) override {
140 ui::LayerAnimationObserver::OnAttachedToSequence(sequence);
141 if (!will_animate_) {
142 tween_type_ = sequence->FirstElement()->tween_type();
143 will_animate_ = true;
144 }
145 }
146
tween_type() const147 gfx::Tween::Type tween_type() const { return tween_type_; }
148
149 private:
150 gfx::Tween::Type tween_type_ = gfx::Tween::LINEAR;
151 aura::Window* window_;
152 bool will_animate_ = false;
153
154 DISALLOW_COPY_AND_ASSIGN(TweenTester);
155 };
156
157 } // namespace
158
159 // TODO(bruthig): Move all non-simple method definitions out of class
160 // declaration.
161 class OverviewSessionTest : public MultiDisplayOverviewAndSplitViewTest {
162 public:
163 OverviewSessionTest() = default;
164 ~OverviewSessionTest() override = default;
165
166 // AshTestBase:
SetUp()167 void SetUp() override {
168 MultiDisplayOverviewAndSplitViewTest::SetUp();
169
170 aura::Env::GetInstance()->set_throttle_input_on_resize_for_testing(false);
171 shelf_view_test_api_ = std::make_unique<ShelfViewTestAPI>(
172 GetPrimaryShelf()->GetShelfViewForTesting());
173 shelf_view_test_api_->SetAnimationDuration(
174 base::TimeDelta::FromMilliseconds(1));
175 ScopedOverviewTransformWindow::SetImmediateCloseForTests(
176 /*immediate=*/true);
177 OverviewWallpaperController::SetDoNotChangeWallpaperForTests();
178 PresentationTimeRecorder::SetReportPresentationTimeImmediatelyForTest(true);
179 }
TearDown()180 void TearDown() override {
181 PresentationTimeRecorder::SetReportPresentationTimeImmediatelyForTest(
182 false);
183 trace_names_.clear();
184 MultiDisplayOverviewAndSplitViewTest::TearDown();
185 }
186
187 // Enters tablet mode. Needed by tests that test dragging and or splitview,
188 // which are tablet mode only.
EnterTabletMode()189 void EnterTabletMode() {
190 // Ensure calls to SetEnabledForTest complete.
191 base::RunLoop().RunUntilIdle();
192 Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
193 base::RunLoop().RunUntilIdle();
194 }
195
WindowsOverlapping(aura::Window * window1,aura::Window * window2)196 bool WindowsOverlapping(aura::Window* window1, aura::Window* window2) {
197 const gfx::Rect window1_bounds = GetTransformedTargetBounds(window1);
198 const gfx::Rect window2_bounds = GetTransformedTargetBounds(window2);
199 return window1_bounds.Intersects(window2_bounds);
200 }
201
overview_controller()202 OverviewController* overview_controller() {
203 return Shell::Get()->overview_controller();
204 }
205
overview_session()206 OverviewSession* overview_session() {
207 return overview_controller()->overview_session_.get();
208 }
209
split_view_controller()210 SplitViewController* split_view_controller() {
211 return SplitViewController::Get(Shell::GetPrimaryRootWindow());
212 }
213
GetTransformedBounds(aura::Window * window)214 gfx::Rect GetTransformedBounds(aura::Window* window) {
215 gfx::Rect bounds_in_screen = window->layer()->bounds();
216 ::wm::ConvertRectToScreen(window->parent(), &bounds_in_screen);
217 gfx::RectF bounds(bounds_in_screen);
218 gfx::Transform transform(gfx::TransformAboutPivot(
219 gfx::ToFlooredPoint(bounds.origin()), window->layer()->transform()));
220 transform.TransformRect(&bounds);
221 return ToStableSizeRoundedRect(bounds);
222 }
223
GetTransformedTargetBounds(aura::Window * window)224 gfx::Rect GetTransformedTargetBounds(aura::Window* window) {
225 gfx::Rect bounds_in_screen = window->layer()->GetTargetBounds();
226 ::wm::ConvertRectToScreen(window->parent(), &bounds_in_screen);
227 gfx::RectF bounds(bounds_in_screen);
228 gfx::Transform transform(
229 gfx::TransformAboutPivot(gfx::ToFlooredPoint(bounds.origin()),
230 window->layer()->GetTargetTransform()));
231 transform.TransformRect(&bounds);
232 return ToStableSizeRoundedRect(bounds);
233 }
234
GetTransformedBoundsInRootWindow(aura::Window * window)235 gfx::Rect GetTransformedBoundsInRootWindow(aura::Window* window) {
236 gfx::RectF bounds = gfx::RectF(gfx::SizeF(window->bounds().size()));
237 aura::Window* root = window->GetRootWindow();
238 CHECK(window->layer());
239 CHECK(root->layer());
240 gfx::Transform transform;
241 if (!window->layer()->GetTargetTransformRelativeTo(root->layer(),
242 &transform)) {
243 return gfx::Rect();
244 }
245 transform.TransformRect(&bounds);
246 return gfx::ToEnclosingRect(bounds);
247 }
248
ClickWindow(aura::Window * window)249 void ClickWindow(aura::Window* window) {
250 ui::test::EventGenerator event_generator(window->GetRootWindow(), window);
251 event_generator.ClickLeftButton();
252 }
253
InOverviewSession()254 bool InOverviewSession() {
255 return overview_controller()->InOverviewSession();
256 }
257
GetDropTarget(int grid_index)258 OverviewItem* GetDropTarget(int grid_index) {
259 return overview_session()->grid_list_[grid_index]->GetDropTarget();
260 }
261
GetCloseButton(OverviewItem * item)262 views::ImageButton* GetCloseButton(OverviewItem* item) {
263 return item->overview_item_view_->close_button();
264 }
265
GetLabelView(OverviewItem * item)266 views::Label* GetLabelView(OverviewItem* item) {
267 return item->overview_item_view_->title_label();
268 }
269
GetBackdropView(OverviewItem * item)270 views::View* GetBackdropView(OverviewItem* item) {
271 return item->overview_item_view_->backdrop_view();
272 }
273
GetPreviewView(OverviewItem * item)274 WindowPreviewView* GetPreviewView(OverviewItem* item) {
275 return item->overview_item_view_->preview_view();
276 }
277
GetCloseButtonOpacity(OverviewItem * item)278 float GetCloseButtonOpacity(OverviewItem* item) {
279 return GetCloseButton(item)->layer()->opacity();
280 }
281
GetTitlebarOpacity(OverviewItem * item)282 float GetTitlebarOpacity(OverviewItem* item) {
283 return item->overview_item_view_->header_view()->layer()->opacity();
284 }
285
286 // Tests that a window is contained within a given OverviewItem, and that both
287 // the window and its matching close button are within the same screen.
CheckWindowAndCloseButtonInScreen(aura::Window * window,OverviewItem * window_item)288 void CheckWindowAndCloseButtonInScreen(aura::Window* window,
289 OverviewItem* window_item) {
290 const gfx::Rect screen_bounds =
291 window_item->root_window()->GetBoundsInScreen();
292 EXPECT_TRUE(window_item->Contains(window));
293 EXPECT_TRUE(screen_bounds.Contains(GetTransformedTargetBounds(window)));
294 EXPECT_TRUE(screen_bounds.Contains(
295 GetCloseButton(window_item)->GetBoundsInScreen()));
296 }
297
SetGridBounds(OverviewGrid * grid,const gfx::Rect & bounds)298 void SetGridBounds(OverviewGrid* grid, const gfx::Rect& bounds) {
299 grid->bounds_ = bounds;
300 }
301
GetGridBounds()302 gfx::Rect GetGridBounds() {
303 if (overview_session())
304 return overview_session()->grid_list_[0]->bounds_;
305
306 return gfx::Rect();
307 }
308
transform_window(OverviewItem * item) const309 const ScopedOverviewTransformWindow& transform_window(
310 OverviewItem* item) const {
311 return item->transform_window_;
312 }
313
CheckOverviewEnterExitHistogram(const char * trace,std::vector<int> && enter_counts,std::vector<int> && exit_counts)314 void CheckOverviewEnterExitHistogram(const char* trace,
315 std::vector<int>&& enter_counts,
316 std::vector<int>&& exit_counts) {
317 CheckForDuplicateTraceName(trace);
318
319 // Overview histograms recorded via ui::ThroughputTracker is reported
320 // on the next frame presented after animation stops. Wait for the next
321 // frame with a 100ms timeout for the report, regardless of whether there
322 // is a next frame.
323 ignore_result(ui::WaitForNextFrameToBePresented(
324 Shell::GetPrimaryRootWindow()->layer()->GetCompositor(),
325 base::TimeDelta::FromMilliseconds(100)));
326
327 {
328 SCOPED_TRACE(trace + std::string(".Enter"));
329 CheckOverviewHistogram("Ash.Overview.AnimationSmoothness.Enter",
330 std::move(enter_counts));
331 }
332 {
333 SCOPED_TRACE(trace + std::string(".Exit"));
334 CheckOverviewHistogram("Ash.Overview.AnimationSmoothness.Exit",
335 std::move(exit_counts));
336 }
337 }
338
339 // Creates a window which cannot be snapped by splitview.
CreateUnsnappableWindow(const gfx::Rect & bounds=gfx::Rect ())340 std::unique_ptr<aura::Window> CreateUnsnappableWindow(
341 const gfx::Rect& bounds = gfx::Rect()) {
342 std::unique_ptr<aura::Window> window = CreateTestWindow(bounds);
343 window->SetProperty(aura::client::kResizeBehaviorKey,
344 aura::client::kResizeBehaviorNone);
345 return window;
346 }
347
HasRoundedCorner(OverviewItem * item)348 bool HasRoundedCorner(OverviewItem* item) {
349 const ui::Layer* layer = item->transform_window_.IsMinimized()
350 ? GetPreviewView(item)->layer()
351 : transform_window(item).window()->layer();
352 return !layer->rounded_corner_radii().IsEmpty();
353 }
354
StubForTest(ExitWarningHandler * ewh)355 static void StubForTest(ExitWarningHandler* ewh) {
356 ewh->stub_timer_for_test_ = true;
357 }
is_ui_shown(ExitWarningHandler * ewh)358 static bool is_ui_shown(ExitWarningHandler* ewh) { return !!ewh->widget_; }
359
360 protected:
CheckForDuplicateTraceName(const char * trace)361 void CheckForDuplicateTraceName(const char* trace) {
362 DCHECK(!base::Contains(trace_names_, trace)) << trace;
363 trace_names_.push_back(trace);
364 }
365
366 base::HistogramTester histograms_;
367
368 private:
CheckOverviewHistogram(const char * histogram,std::vector<int> && counts)369 void CheckOverviewHistogram(const char* histogram,
370 std::vector<int>&& counts) {
371 ASSERT_EQ(5u, counts.size());
372
373 histograms_.ExpectTotalCount(histogram + std::string(".ClamshellMode"),
374 counts[0]);
375 histograms_.ExpectTotalCount(
376 histogram + std::string(".SingleClamshellMode"), counts[1]);
377 histograms_.ExpectTotalCount(histogram + std::string(".TabletMode"),
378 counts[2]);
379 histograms_.ExpectTotalCount(
380 histogram + std::string(".MinimizedTabletMode"), counts[3]);
381 histograms_.ExpectTotalCount(histogram + std::string(".SplitView"),
382 counts[4]);
383 }
384
385 std::unique_ptr<ShelfViewTestAPI> shelf_view_test_api_;
386 std::vector<std::string> trace_names_;
387
388 DISALLOW_COPY_AND_ASSIGN(OverviewSessionTest);
389 };
390
391 // Tests that an a11y alert is sent on entering overview mode.
TEST_P(OverviewSessionTest,A11yAlertOnOverviewMode)392 TEST_P(OverviewSessionTest, A11yAlertOnOverviewMode) {
393 TestAccessibilityControllerClient client;
394 std::unique_ptr<aura::Window> window(CreateTestWindow());
395 EXPECT_NE(AccessibilityAlert::WINDOW_OVERVIEW_MODE_ENTERED,
396 client.last_a11y_alert());
397 ToggleOverview();
398 EXPECT_EQ(AccessibilityAlert::WINDOW_OVERVIEW_MODE_ENTERED,
399 client.last_a11y_alert());
400 }
401
402 // Tests that there are no crashes when there is not enough screen space
403 // available to show all of the windows.
TEST_P(OverviewSessionTest,SmallDisplay)404 TEST_P(OverviewSessionTest, SmallDisplay) {
405 UpdateDisplay("3x1");
406 gfx::Rect bounds(0, 0, 1, 1);
407 std::unique_ptr<aura::Window> window1(CreateTestWindow(bounds));
408 std::unique_ptr<aura::Window> window2(CreateTestWindow(bounds));
409 std::unique_ptr<aura::Window> window3(CreateTestWindow(bounds));
410 std::unique_ptr<aura::Window> window4(CreateTestWindow(bounds));
411 window1->SetProperty(aura::client::kTopViewInset, 0);
412 window2->SetProperty(aura::client::kTopViewInset, 0);
413 window3->SetProperty(aura::client::kTopViewInset, 0);
414 window4->SetProperty(aura::client::kTopViewInset, 0);
415 ToggleOverview();
416 }
417
418 // Tests entering overview mode with two windows and selecting one by clicking.
TEST_P(OverviewSessionTest,Basic)419 TEST_P(OverviewSessionTest, Basic) {
420 ui::ScopedAnimationDurationScaleMode anmatin_scale(
421 ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
422
423 // Overview disabled by default.
424 EXPECT_FALSE(InOverviewSession());
425
426 aura::Window* root_window = Shell::GetPrimaryRootWindow();
427 std::unique_ptr<aura::Window> window1(CreateTestWindow());
428 std::unique_ptr<aura::Window> window2(CreateTestWindow());
429
430 EXPECT_TRUE(WindowsOverlapping(window1.get(), window2.get()));
431 wm::ActivateWindow(window2.get());
432 EXPECT_FALSE(wm::IsActiveWindow(window1.get()));
433 EXPECT_TRUE(wm::IsActiveWindow(window2.get()));
434 EXPECT_EQ(window2.get(), window_util::GetFocusedWindow());
435
436 // Hide the cursor before entering overview to test that it will be shown.
437 aura::client::GetCursorClient(root_window)->HideCursor();
438
439 CheckOverviewEnterExitHistogram("Init", {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0});
440 // In overview mode the windows should no longer overlap and the overview
441 // focus window should be focused.
442 ToggleOverview();
443 WaitForOverviewEnterAnimation();
444
445 EXPECT_EQ(overview_session()->GetOverviewFocusWindow(),
446 window_util::GetFocusedWindow());
447 EXPECT_FALSE(WindowsOverlapping(window1.get(), window2.get()));
448 CheckOverviewEnterExitHistogram("Enter", {1, 0, 0, 0, 0}, {0, 0, 0, 0, 0});
449
450 // Clicking window 1 should activate it.
451 ClickWindow(window1.get());
452 WaitForOverviewExitAnimation();
453
454 EXPECT_TRUE(wm::IsActiveWindow(window1.get()));
455 EXPECT_FALSE(wm::IsActiveWindow(window2.get()));
456 EXPECT_EQ(window1.get(), window_util::GetFocusedWindow());
457
458 // Cursor should have been unlocked.
459 EXPECT_FALSE(aura::client::GetCursorClient(root_window)->IsCursorLocked());
460
461 CheckOverviewEnterExitHistogram("Exit", {1, 0, 0, 0, 0}, {1, 0, 0, 0, 0});
462 }
463
464 // Tests activating minimized window.
TEST_P(OverviewSessionTest,ActivateMinimized)465 TEST_P(OverviewSessionTest, ActivateMinimized) {
466 std::unique_ptr<aura::Window> window(CreateTestWindow());
467
468 WindowState* window_state = WindowState::Get(window.get());
469 WMEvent minimize_event(WM_EVENT_MINIMIZE);
470 window_state->OnWMEvent(&minimize_event);
471 EXPECT_FALSE(window->IsVisible());
472 EXPECT_EQ(0.f, window->layer()->GetTargetOpacity());
473 EXPECT_EQ(WindowStateType::kMinimized,
474 WindowState::Get(window.get())->GetStateType());
475
476 ToggleOverview();
477
478 EXPECT_FALSE(window->IsVisible());
479 EXPECT_EQ(0.f, window->layer()->GetTargetOpacity());
480 EXPECT_EQ(WindowStateType::kMinimized, window_state->GetStateType());
481 WindowPreviewView* preview_view =
482 GetPreviewView(GetOverviewItemForWindow(window.get()));
483 EXPECT_TRUE(preview_view);
484
485 const gfx::Point point = preview_view->GetBoundsInScreen().CenterPoint();
486 GetEventGenerator()->set_current_screen_location(point);
487 GetEventGenerator()->ClickLeftButton();
488
489 EXPECT_FALSE(InOverviewSession());
490
491 EXPECT_TRUE(window->IsVisible());
492 EXPECT_EQ(1.f, window->layer()->GetTargetOpacity());
493 EXPECT_EQ(WindowStateType::kNormal, window_state->GetStateType());
494 }
495
496 // Tests that the ordering of windows is stable across different overview
497 // sessions even when the windows have the same bounds.
TEST_P(OverviewSessionTest,WindowsOrder)498 TEST_P(OverviewSessionTest, WindowsOrder) {
499 std::unique_ptr<aura::Window> window1(CreateTestWindowInShellWithId(1));
500 std::unique_ptr<aura::Window> window2(CreateTestWindowInShellWithId(2));
501 std::unique_ptr<aura::Window> window3(CreateTestWindowInShellWithId(3));
502
503 // The order of windows in overview mode is MRU.
504 WindowState::Get(window1.get())->Activate();
505 ToggleOverview();
506 const std::vector<std::unique_ptr<OverviewItem>>& overview1 =
507 GetOverviewItemsForRoot(0);
508 EXPECT_EQ(1, overview1[0]->GetWindow()->id());
509 EXPECT_EQ(3, overview1[1]->GetWindow()->id());
510 EXPECT_EQ(2, overview1[2]->GetWindow()->id());
511 ToggleOverview();
512
513 // Activate the second window.
514 WindowState::Get(window2.get())->Activate();
515 ToggleOverview();
516 const std::vector<std::unique_ptr<OverviewItem>>& overview2 =
517 GetOverviewItemsForRoot(0);
518
519 // The order should be MRU.
520 EXPECT_EQ(2, overview2[0]->GetWindow()->id());
521 EXPECT_EQ(1, overview2[1]->GetWindow()->id());
522 EXPECT_EQ(3, overview2[2]->GetWindow()->id());
523 ToggleOverview();
524 }
525
526 // Tests selecting a window by tapping on it.
TEST_P(OverviewSessionTest,BasicGesture)527 TEST_P(OverviewSessionTest, BasicGesture) {
528 std::unique_ptr<aura::Window> window1(CreateTestWindow());
529 std::unique_ptr<aura::Window> window2(CreateTestWindow());
530 wm::ActivateWindow(window1.get());
531 EXPECT_EQ(window1.get(), window_util::GetFocusedWindow());
532 ToggleOverview();
533 EXPECT_EQ(overview_session()->GetOverviewFocusWindow(),
534 window_util::GetFocusedWindow());
535 GetEventGenerator()->GestureTapAt(
536 GetTransformedTargetBounds(window2.get()).CenterPoint());
537 EXPECT_EQ(window2.get(), window_util::GetFocusedWindow());
538 }
539
540 // Tests that the user action WindowSelector_ActiveWindowChanged is
541 // recorded when the mouse/touchscreen/keyboard are used to select a window
542 // in overview mode which is different from the previously-active window.
TEST_P(OverviewSessionTest,ActiveWindowChangedUserActionRecorded)543 TEST_P(OverviewSessionTest, ActiveWindowChangedUserActionRecorded) {
544 base::UserActionTester user_action_tester;
545 std::unique_ptr<aura::Window> window1(CreateTestWindow());
546 std::unique_ptr<aura::Window> window2(CreateTestWindow());
547 wm::ActivateWindow(window1.get());
548 ToggleOverview();
549
550 // Tap on |window2| to activate it and exit overview.
551 GetEventGenerator()->GestureTapAt(
552 GetTransformedTargetBounds(window2.get()).CenterPoint());
553 EXPECT_EQ(
554 1, user_action_tester.GetActionCount(kActiveWindowChangedFromOverview));
555
556 // Click on |window2| to activate it and exit overview.
557 wm::ActivateWindow(window1.get());
558 ToggleOverview();
559 ClickWindow(window2.get());
560 EXPECT_EQ(
561 2, user_action_tester.GetActionCount(kActiveWindowChangedFromOverview));
562
563 // Highlight |window2| using the arrow keys. Activate it (and exit overview)
564 // by pressing the return key.
565 wm::ActivateWindow(window1.get());
566 ToggleOverview();
567 ASSERT_TRUE(HighlightOverviewWindow(window2.get()));
568 SendKey(ui::VKEY_RETURN);
569 EXPECT_EQ(
570 3, user_action_tester.GetActionCount(kActiveWindowChangedFromOverview));
571 }
572
573 // Tests that the user action WindowSelector_ActiveWindowChanged is not
574 // recorded when the mouse/touchscreen/keyboard are used to select the
575 // already-active window from overview mode. Also verifies that entering and
576 // exiting overview without selecting a window does not record the action.
TEST_P(OverviewSessionTest,ActiveWindowChangedUserActionNotRecorded)577 TEST_P(OverviewSessionTest, ActiveWindowChangedUserActionNotRecorded) {
578 base::UserActionTester user_action_tester;
579 std::unique_ptr<aura::Window> window1(CreateTestWindow());
580 std::unique_ptr<aura::Window> window2(CreateTestWindow());
581 wm::ActivateWindow(window1.get());
582 ToggleOverview();
583
584 // Tap on |window1| to exit overview.
585 GetEventGenerator()->GestureTapAt(
586 GetTransformedTargetBounds(window1.get()).CenterPoint());
587 EXPECT_EQ(
588 0, user_action_tester.GetActionCount(kActiveWindowChangedFromOverview));
589
590 // |window1| remains active. Click on it to exit overview.
591 ASSERT_EQ(window1.get(), window_util::GetFocusedWindow());
592 ToggleOverview();
593 ClickWindow(window1.get());
594 EXPECT_EQ(
595 0, user_action_tester.GetActionCount(kActiveWindowChangedFromOverview));
596
597 // |window1| remains active. Select using the keyboard.
598 ASSERT_EQ(window1.get(), window_util::GetFocusedWindow());
599 ToggleOverview();
600 ASSERT_TRUE(HighlightOverviewWindow(window1.get()));
601 SendKey(ui::VKEY_RETURN);
602 EXPECT_EQ(
603 0, user_action_tester.GetActionCount(kActiveWindowChangedFromOverview));
604
605 // Entering and exiting overview without user input should not record
606 // the action.
607 ToggleOverview();
608 ToggleOverview();
609 EXPECT_EQ(
610 0, user_action_tester.GetActionCount(kActiveWindowChangedFromOverview));
611 }
612
613 // Tests that the user action WindowSelector_ActiveWindowChanged is not
614 // recorded when overview mode exits as a result of closing its only window.
TEST_P(OverviewSessionTest,ActiveWindowChangedUserActionWindowClose)615 TEST_P(OverviewSessionTest, ActiveWindowChangedUserActionWindowClose) {
616 base::UserActionTester user_action_tester;
617 std::unique_ptr<views::Widget> widget(CreateTestWidget(
618 nullptr, desks_util::GetActiveDeskContainerId(), gfx::Rect(400, 400)));
619
620 ToggleOverview();
621 aura::Window* window = widget->GetNativeWindow();
622 const gfx::Point point = GetCloseButton(GetOverviewItemForWindow(window))
623 ->GetBoundsInScreen()
624 .CenterPoint();
625 ASSERT_FALSE(widget->IsClosed());
626 GetEventGenerator()->set_current_screen_location(point);
627 GetEventGenerator()->ClickLeftButton();
628 ASSERT_TRUE(widget->IsClosed());
629 EXPECT_EQ(
630 0, user_action_tester.GetActionCount(kActiveWindowChangedFromOverview));
631 }
632
633 // Tests that we do not crash and overview mode remains engaged if the desktop
634 // is tapped while a finger is already down over a window.
TEST_P(OverviewSessionTest,NoCrashWithDesktopTap)635 TEST_P(OverviewSessionTest, NoCrashWithDesktopTap) {
636 std::unique_ptr<aura::Window> window(
637 CreateTestWindow(gfx::Rect(200, 300, 250, 450)));
638
639 ToggleOverview();
640
641 const gfx::Rect bounds = GetTransformedBoundsInRootWindow(window.get());
642 GetEventGenerator()->set_current_screen_location(bounds.CenterPoint());
643
644 // Press down on the window.
645 const int kTouchId = 19;
646 GetEventGenerator()->PressTouchId(kTouchId);
647
648 // Tap on the desktop, which should not cause a crash. Overview mode should
649 // remain engaged.
650 GetEventGenerator()->GestureTapAt(GetGridBounds().CenterPoint());
651 EXPECT_TRUE(InOverviewSession());
652
653 GetEventGenerator()->ReleaseTouchId(kTouchId);
654 }
655
656 // Tests that we do not crash and a window is selected when appropriate when
657 // we click on a window during touch.
TEST_P(OverviewSessionTest,ClickOnWindowDuringTouch)658 TEST_P(OverviewSessionTest, ClickOnWindowDuringTouch) {
659 std::unique_ptr<aura::Window> window1(CreateTestWindow());
660 std::unique_ptr<aura::Window> window2(CreateTestWindow());
661 wm::ActivateWindow(window2.get());
662 EXPECT_FALSE(wm::IsActiveWindow(window1.get()));
663 EXPECT_TRUE(wm::IsActiveWindow(window2.get()));
664
665 ToggleOverview();
666
667 gfx::Rect window1_bounds = GetTransformedBoundsInRootWindow(window1.get());
668 GetEventGenerator()->set_current_screen_location(
669 window1_bounds.CenterPoint());
670
671 // Clicking on |window2| while touching on |window1| should not cause a
672 // crash, it should do nothing since overview only handles one click or touch
673 // at a time.
674 const int kTouchId = 19;
675 GetEventGenerator()->PressTouchId(kTouchId);
676 GetEventGenerator()->MoveMouseToCenterOf(window2.get());
677 GetEventGenerator()->ClickLeftButton();
678 EXPECT_TRUE(InOverviewSession());
679 EXPECT_FALSE(wm::IsActiveWindow(window2.get()));
680
681 // Clicking on |window1| while touching on |window1| should not cause
682 // a crash, overview mode should be disengaged, and |window1| should
683 // be active.
684 GetEventGenerator()->MoveMouseToCenterOf(window1.get());
685 GetEventGenerator()->ClickLeftButton();
686 EXPECT_FALSE(InOverviewSession());
687 EXPECT_TRUE(wm::IsActiveWindow(window1.get()));
688 GetEventGenerator()->ReleaseTouchId(kTouchId);
689 }
690
691 // Tests that a window does not receive located events when in overview mode.
TEST_P(OverviewSessionTest,WindowDoesNotReceiveEvents)692 TEST_P(OverviewSessionTest, WindowDoesNotReceiveEvents) {
693 std::unique_ptr<aura::Window> window(CreateTestWindow(gfx::Rect(400, 400)));
694 const gfx::Point point1 = window->bounds().CenterPoint();
695 ui::MouseEvent event1(ui::ET_MOUSE_PRESSED, point1, point1,
696 ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE);
697
698 aura::Window* root_window = Shell::GetPrimaryRootWindow();
699 ui::EventTarget* root_target = root_window;
700 ui::EventTargeter* targeter =
701 root_window->GetHost()->dispatcher()->GetDefaultEventTargeter();
702
703 // The event should target the window because we are still not in overview
704 // mode.
705 EXPECT_EQ(window.get(), targeter->FindTargetForEvent(root_target, &event1));
706
707 ToggleOverview();
708
709 // The bounds have changed, take that into account.
710 const gfx::Point point2 =
711 GetTransformedBoundsInRootWindow(window.get()).CenterPoint();
712 ui::MouseEvent event2(ui::ET_MOUSE_PRESSED, point2, point2,
713 ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE);
714
715 // Now the transparent window should be intercepting this event.
716 EXPECT_NE(window.get(), targeter->FindTargetForEvent(root_target, &event2));
717 }
718
719 // Tests that clicking on the close button effectively closes the window.
TEST_P(OverviewSessionTest,CloseButton)720 TEST_P(OverviewSessionTest, CloseButton) {
721 std::unique_ptr<views::Widget> widget(CreateTestWidget());
722 std::unique_ptr<views::Widget> minimized_widget(CreateTestWidget());
723 minimized_widget->Minimize();
724
725 ToggleOverview();
726 aura::Window* window = widget->GetNativeWindow();
727 const gfx::Point point = GetCloseButton(GetOverviewItemForWindow(window))
728 ->GetBoundsInScreen()
729 .CenterPoint();
730 GetEventGenerator()->set_current_screen_location(point);
731
732 EXPECT_FALSE(widget->IsClosed());
733 GetEventGenerator()->ClickLeftButton();
734 EXPECT_TRUE(widget->IsClosed());
735 ASSERT_TRUE(InOverviewSession());
736
737 aura::Window* minimized_window = minimized_widget->GetNativeWindow();
738 WindowPreviewView* preview_view =
739 GetPreviewView(GetOverviewItemForWindow(minimized_window));
740 EXPECT_TRUE(preview_view);
741 const gfx::Point point2 =
742 GetCloseButton(GetOverviewItemForWindow(minimized_window))
743 ->GetBoundsInScreen()
744 .CenterPoint();
745 GetEventGenerator()->MoveMouseTo(point2);
746 EXPECT_FALSE(minimized_widget->IsClosed());
747
748 GetEventGenerator()->ClickLeftButton();
749 EXPECT_TRUE(minimized_widget->IsClosed());
750
751 // All minimized windows are closed, so it should exit overview mode.
752 base::RunLoop().RunUntilIdle();
753 EXPECT_FALSE(InOverviewSession());
754 }
755
756 // Tests that the shadow disappears before the close animation starts.
757 // Regression test for https://crbug.com/981509.
TEST_P(OverviewSessionTest,CloseAnimationShadow)758 TEST_P(OverviewSessionTest, CloseAnimationShadow) {
759 // Give us some time to check if the shadow has disappeared.
760 ScopedOverviewTransformWindow::SetImmediateCloseForTests(/*immediate=*/false);
761 ui::ScopedAnimationDurationScaleMode test_duration_mode(
762 ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
763
764 std::unique_ptr<views::Widget> widget = CreateTestWidget();
765
766 ToggleOverview();
767 ShellTestApi().WaitForOverviewAnimationState(
768 OverviewAnimationState::kEnterAnimationComplete);
769 // Click the close button.
770 OverviewItem* item = GetOverviewItemForWindow(widget->GetNativeWindow());
771 const gfx::Point point =
772 GetCloseButton(item)->GetBoundsInScreen().CenterPoint();
773 GetEventGenerator()->set_current_screen_location(point);
774 GetEventGenerator()->ClickLeftButton();
775 ASSERT_FALSE(widget->IsClosed());
776 ASSERT_TRUE(InOverviewSession());
777
778 // The shadow bounds are empty, which means its not visible.
779 EXPECT_EQ(gfx::Rect(), item->GetShadowBoundsForTesting());
780 }
781
782 // Tests minimizing/unminimizing in overview mode.
TEST_P(OverviewSessionTest,MinimizeUnminimize)783 TEST_P(OverviewSessionTest, MinimizeUnminimize) {
784 std::unique_ptr<views::Widget> widget(CreateTestWidget());
785 aura::Window* window = widget->GetNativeWindow();
786
787 ToggleOverview();
788 EXPECT_FALSE(GetPreviewView(GetOverviewItemForWindow(window)));
789
790 widget->Minimize();
791 EXPECT_TRUE(widget->IsMinimized());
792 EXPECT_TRUE(InOverviewSession());
793 EXPECT_TRUE(GetPreviewView(GetOverviewItemForWindow(window)));
794
795 widget->Restore();
796 EXPECT_FALSE(widget->IsMinimized());
797 EXPECT_FALSE(GetPreviewView(GetOverviewItemForWindow(window)));
798 EXPECT_TRUE(InOverviewSession());
799 }
800
801 // Tests that clicking on the close button on a secondary display effectively
802 // closes the window.
TEST_P(OverviewSessionTest,CloseButtonOnMultipleDisplay)803 TEST_P(OverviewSessionTest, CloseButtonOnMultipleDisplay) {
804 UpdateDisplay("600x400,600x400");
805
806 // We need a widget for the close button to work because windows are closed
807 // via the widget. We also use the widget to determine if the window has been
808 // closed or not. Parent the window to a window in a non-primary root window.
809 std::unique_ptr<aura::Window> window(
810 CreateTestWindow(gfx::Rect(650, 300, 250, 450)));
811 std::unique_ptr<views::Widget> widget(CreateTestWidget());
812 widget->SetBounds(gfx::Rect(650, 0, 400, 400));
813 aura::Window* window2 = widget->GetNativeWindow();
814 window2->SetProperty(aura::client::kTopViewInset, kHeaderHeightDp);
815 views::Widget::ReparentNativeView(window2, window->parent());
816 ASSERT_EQ(Shell::GetAllRootWindows()[1], window2->GetRootWindow());
817
818 ToggleOverview();
819 gfx::Rect bounds = GetTransformedBoundsInRootWindow(window2);
820 gfx::Point point(bounds.right() - 5, bounds.y() + 5);
821 ui::test::EventGenerator event_generator(window2->GetRootWindow(), point);
822
823 EXPECT_FALSE(widget->IsClosed());
824 event_generator.ClickLeftButton();
825 EXPECT_TRUE(widget->IsClosed());
826 }
827
828 // Tests entering overview mode with two windows and selecting one.
TEST_P(OverviewSessionTest,FullscreenWindow)829 TEST_P(OverviewSessionTest, FullscreenWindow) {
830 ui::ScopedAnimationDurationScaleMode anmatin_scale(
831 ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
832
833 std::unique_ptr<aura::Window> window1(CreateTestWindow());
834 std::unique_ptr<aura::Window> window2(CreateTestWindow());
835 wm::ActivateWindow(window1.get());
836
837 const WMEvent toggle_fullscreen_event(WM_EVENT_TOGGLE_FULLSCREEN);
838 WindowState::Get(window1.get())->OnWMEvent(&toggle_fullscreen_event);
839 EXPECT_TRUE(WindowState::Get(window1.get())->IsFullscreen());
840
841 // Enter overview and select the fullscreen window.
842 ToggleOverview();
843 WaitForOverviewEnterAnimation();
844 CheckOverviewEnterExitHistogram("FullscreenWindowEnter1", {0, 1, 0, 0, 0},
845 {0, 0, 0, 0, 0});
846 ClickWindow(window1.get());
847 WaitForOverviewExitAnimation();
848 EXPECT_TRUE(WindowState::Get(window1.get())->IsFullscreen());
849 CheckOverviewEnterExitHistogram("FullscreenWindowExit1", {0, 1, 0, 0, 0},
850 {0, 1, 0, 0, 0});
851
852 // Entering overview and selecting another window, the previous window remains
853 // fullscreen.
854 ToggleOverview();
855 WaitForOverviewEnterAnimation();
856 CheckOverviewEnterExitHistogram("FullscreenWindowEnter2", {0, 2, 0, 0, 0},
857 {0, 1, 0, 0, 0});
858 ClickWindow(window2.get());
859 WaitForOverviewExitAnimation();
860 EXPECT_TRUE(WindowState::Get(window1.get())->IsFullscreen());
861 CheckOverviewEnterExitHistogram("FullscreenWindowExit2", {0, 2, 0, 0, 0},
862 {1, 1, 0, 0, 0});
863 }
864
865 // Tests entering overview mode with maximized window.
TEST_P(OverviewSessionTest,MaximizedWindow)866 TEST_P(OverviewSessionTest, MaximizedWindow) {
867 ui::ScopedAnimationDurationScaleMode anmatin_scale(
868 ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
869
870 std::unique_ptr<aura::Window> window1(CreateTestWindow());
871 std::unique_ptr<aura::Window> window2(CreateTestWindow());
872 wm::ActivateWindow(window1.get());
873
874 const WMEvent maximize_event(WM_EVENT_MAXIMIZE);
875 WindowState::Get(window1.get())->OnWMEvent(&maximize_event);
876 EXPECT_TRUE(WindowState::Get(window1.get())->IsMaximized());
877
878 // Enter overview and select the fullscreen window.
879 ToggleOverview();
880 WaitForOverviewEnterAnimation();
881 CheckOverviewEnterExitHistogram("MaximizedWindowEnter1", {0, 1, 0, 0, 0},
882 {0, 0, 0, 0, 0});
883 ClickWindow(window1.get());
884 WaitForOverviewExitAnimation();
885 EXPECT_TRUE(WindowState::Get(window1.get())->IsMaximized());
886 CheckOverviewEnterExitHistogram("MaximizedWindowExit1", {0, 1, 0, 0, 0},
887 {0, 1, 0, 0, 0});
888
889 ToggleOverview();
890 WaitForOverviewEnterAnimation();
891 CheckOverviewEnterExitHistogram("MaximizedWindowEnter2", {0, 2, 0, 0, 0},
892 {0, 1, 0, 0, 0});
893 ClickWindow(window2.get());
894 WaitForOverviewExitAnimation();
895 EXPECT_TRUE(WindowState::Get(window1.get())->IsMaximized());
896 CheckOverviewEnterExitHistogram("MaximizedWindowExit2", {0, 2, 0, 0, 0},
897 {1, 1, 0, 0, 0});
898 }
899
TEST_P(OverviewSessionTest,TabletModeHistograms)900 TEST_P(OverviewSessionTest, TabletModeHistograms) {
901 ui::ScopedAnimationDurationScaleMode anmatin_scale(
902 ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
903
904 EnterTabletMode();
905 std::unique_ptr<aura::Window> window1(CreateTestWindow());
906
907 // Enter overview with the window maximized.
908 ToggleOverview();
909 WaitForOverviewEnterAnimation();
910 CheckOverviewEnterExitHistogram("MaximizedWindowTabletEnter", {0, 0, 1, 0, 0},
911 {0, 0, 0, 0, 0});
912
913 ToggleOverview();
914 WaitForOverviewExitAnimation();
915 CheckOverviewEnterExitHistogram("MaximizedWindowTabletExit", {0, 0, 1, 0, 0},
916 {0, 0, 1, 0, 0});
917
918 WindowState::Get(window1.get())->Minimize();
919 ToggleOverview();
920 WaitForOverviewEnterAnimation();
921 CheckOverviewEnterExitHistogram("MinimizedWindowTabletEnter", {0, 0, 1, 1, 0},
922 {0, 0, 1, 0, 0});
923
924 ToggleOverview();
925 WaitForOverviewExitAnimation();
926 CheckOverviewEnterExitHistogram("MinimizedWindowTabletExit", {0, 0, 1, 1, 0},
927 {0, 0, 1, 1, 0});
928 }
929
930 // Tests that entering overview when a fullscreen window is active in maximized
931 // mode correctly applies the transformations to the window and correctly
932 // updates the window bounds on exiting overview mode: http://crbug.com/401664.
TEST_P(OverviewSessionTest,FullscreenWindowTabletMode)933 TEST_P(OverviewSessionTest, FullscreenWindowTabletMode) {
934 ui::ScopedAnimationDurationScaleMode anmatin_scale(
935 ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
936
937 UpdateDisplay("800x600");
938 const gfx::Rect bounds(400, 400);
939 std::unique_ptr<aura::Window> window1(CreateTestWindow(bounds));
940 std::unique_ptr<aura::Window> window2(CreateTestWindow(bounds));
941 wm::ActivateWindow(window2.get());
942 wm::ActivateWindow(window1.get());
943
944 EnterTabletMode();
945 gfx::Rect normal_window_bounds(window1->bounds());
946 const WMEvent toggle_fullscreen_event(WM_EVENT_TOGGLE_FULLSCREEN);
947 WindowState::Get(window1.get())->OnWMEvent(&toggle_fullscreen_event);
948
949 // Finish fullscreen state change animation since it is irrelevant.
950 window1->layer()->GetAnimator()->StopAnimating();
951
952 gfx::Rect fullscreen_window_bounds(window1->bounds());
953 EXPECT_NE(normal_window_bounds, fullscreen_window_bounds);
954 EXPECT_EQ(fullscreen_window_bounds, window2->GetTargetBounds());
955
956 const gfx::Rect fullscreen(800, 600);
957 const int shelf_inset = 600 - ShelfConfig::Get()->shelf_size();
958 const gfx::Rect normal_work_area(800, shelf_inset);
959 display::Screen* screen = display::Screen::GetScreen();
960 EXPECT_EQ(gfx::Rect(800, 600),
961 screen->GetDisplayNearestWindow(window1.get()).work_area());
962 ToggleOverview();
963 WaitForOverviewEnterAnimation();
964 EXPECT_EQ(fullscreen,
965 screen->GetDisplayNearestWindow(window1.get()).work_area());
966 CheckOverviewEnterExitHistogram("FullscreenWindowTabletEnter1",
967 {0, 0, 1, 0, 0}, {0, 0, 0, 0, 0});
968
969 // Window 2 would normally resize to normal window bounds on showing the shelf
970 // for overview but this is deferred until overview is exited.
971 EXPECT_EQ(fullscreen_window_bounds, window2->GetTargetBounds());
972 EXPECT_FALSE(WindowsOverlapping(window1.get(), window2.get()));
973 ToggleOverview();
974 WaitForOverviewExitAnimation();
975 EXPECT_EQ(fullscreen,
976 screen->GetDisplayNearestWindow(window1.get()).work_area());
977 // Since the fullscreen window is still active, window2 will still have the
978 // larger bounds.
979 EXPECT_EQ(fullscreen_window_bounds, window2->GetTargetBounds());
980 CheckOverviewEnterExitHistogram("FullscreenWindowTabletExit1",
981 {0, 0, 1, 0, 0}, {0, 0, 1, 0, 0});
982
983 // Enter overview again and select window 2. Selecting window 2 should show
984 // the shelf bringing window2 back to the normal bounds.
985 ToggleOverview();
986 WaitForOverviewEnterAnimation();
987 CheckOverviewEnterExitHistogram("FullscreenWindowTabletEnter2",
988 {0, 0, 2, 0, 0}, {0, 0, 1, 0, 0});
989
990 ClickWindow(window2.get());
991 WaitForOverviewExitAnimation();
992 // Selecting non fullscreen window should set the work area back to normal.
993 EXPECT_EQ(normal_work_area,
994 screen->GetDisplayNearestWindow(window1.get()).work_area());
995 EXPECT_EQ(normal_window_bounds, window2->GetTargetBounds());
996 CheckOverviewEnterExitHistogram("FullscreenWindowTabletExit2",
997 {0, 0, 2, 0, 0}, {0, 0, 2, 0, 0});
998
999 ToggleOverview();
1000 WaitForOverviewEnterAnimation();
1001 CheckOverviewEnterExitHistogram("FullscreenWindowTabletEnter3",
1002 {0, 0, 3, 0, 0}, {0, 0, 2, 0, 0});
1003 EXPECT_EQ(normal_work_area,
1004 screen->GetDisplayNearestWindow(window1.get()).work_area());
1005 ClickWindow(window1.get());
1006 WaitForOverviewExitAnimation();
1007 // Selecting fullscreen. The work area should be updated to fullscreen as
1008 // well.
1009 EXPECT_EQ(fullscreen,
1010 screen->GetDisplayNearestWindow(window1.get()).work_area());
1011 CheckOverviewEnterExitHistogram("FullscreenWindowTabletExit3",
1012 {0, 0, 3, 0, 0}, {0, 0, 3, 0, 0});
1013 }
1014
TEST_P(OverviewSessionTest,SkipOverviewWindow)1015 TEST_P(OverviewSessionTest, SkipOverviewWindow) {
1016 std::unique_ptr<aura::Window> window1(CreateTestWindow());
1017 std::unique_ptr<aura::Window> window2(CreateTestWindow());
1018 window2->SetProperty(kHideInOverviewKey, true);
1019
1020 // Enter overview.
1021 ToggleOverview();
1022 EXPECT_TRUE(window1->IsVisible());
1023 EXPECT_FALSE(window2->IsVisible());
1024
1025 // Exit overview.
1026 ToggleOverview();
1027 base::RunLoop().RunUntilIdle();
1028 EXPECT_TRUE(window1->IsVisible());
1029 EXPECT_TRUE(window2->IsVisible());
1030 }
1031
1032 // Tests that a minimized window's visibility and layer visibility
1033 // stay invisible (A minimized window is cloned during overview).
TEST_P(OverviewSessionTest,MinimizedWindowState)1034 TEST_P(OverviewSessionTest, MinimizedWindowState) {
1035 std::unique_ptr<aura::Window> window1(CreateTestWindow());
1036 WindowState::Get(window1.get())->Minimize();
1037 EXPECT_FALSE(window1->IsVisible());
1038 EXPECT_FALSE(window1->layer()->GetTargetVisibility());
1039
1040 ToggleOverview();
1041 EXPECT_FALSE(window1->IsVisible());
1042 EXPECT_FALSE(window1->layer()->GetTargetVisibility());
1043
1044 ToggleOverview();
1045 EXPECT_FALSE(window1->IsVisible());
1046 EXPECT_FALSE(window1->layer()->GetTargetVisibility());
1047 }
1048
1049 // Tests that a bounds change during overview is corrected for.
TEST_P(OverviewSessionTest,BoundsChangeDuringOverview)1050 TEST_P(OverviewSessionTest, BoundsChangeDuringOverview) {
1051 std::unique_ptr<aura::Window> window(
1052 CreateTestWindowInShellWithDelegate(nullptr, -1, gfx::Rect(400, 400)));
1053 // Use overview headers above the window in this test.
1054 window->SetProperty(aura::client::kTopViewInset, 0);
1055 ToggleOverview();
1056 gfx::Rect overview_bounds = GetTransformedTargetBounds(window.get());
1057 window->SetBounds(gfx::Rect(200, 0, 200, 200));
1058 gfx::Rect new_overview_bounds = GetTransformedTargetBounds(window.get());
1059 EXPECT_EQ(overview_bounds, new_overview_bounds);
1060 ToggleOverview();
1061 }
1062
1063 // Tests that a change to the |kTopViewInset| window property during overview is
1064 // corrected for.
TEST_P(OverviewSessionTest,TopViewInsetChangeDuringOverview)1065 TEST_P(OverviewSessionTest, TopViewInsetChangeDuringOverview) {
1066 std::unique_ptr<aura::Window> window = CreateTestWindow(gfx::Rect(400, 400));
1067 window->SetProperty(aura::client::kTopViewInset, 32);
1068 ToggleOverview();
1069 gfx::Rect overview_bounds = GetTransformedTargetBounds(window.get());
1070 window->SetProperty(aura::client::kTopViewInset, 0);
1071 gfx::Rect new_overview_bounds = GetTransformedTargetBounds(window.get());
1072 EXPECT_NE(overview_bounds, new_overview_bounds);
1073 ToggleOverview();
1074 }
1075
1076 // Tests that a newly created window aborts overview.
TEST_P(OverviewSessionTest,NewWindowCancelsOverview)1077 TEST_P(OverviewSessionTest, NewWindowCancelsOverview) {
1078 std::unique_ptr<aura::Window> window1(CreateTestWindow());
1079 ToggleOverview();
1080 EXPECT_TRUE(InOverviewSession());
1081
1082 // A window being created should exit overview mode.
1083 std::unique_ptr<aura::Window> window2(CreateTestWindow());
1084 EXPECT_FALSE(InOverviewSession());
1085 }
1086
1087 // Tests that a window activation exits overview mode.
TEST_P(OverviewSessionTest,ActivationCancelsOverview)1088 TEST_P(OverviewSessionTest, ActivationCancelsOverview) {
1089 std::unique_ptr<aura::Window> window1(CreateTestWindow());
1090 std::unique_ptr<aura::Window> window2(CreateTestWindow());
1091 window2->Focus();
1092 ToggleOverview();
1093 EXPECT_TRUE(InOverviewSession());
1094
1095 // A window being activated should exit overview mode.
1096 window1->Focus();
1097 EXPECT_FALSE(InOverviewSession());
1098
1099 // window1 should be focused after exiting even though window2 was focused on
1100 // entering overview because we exited due to an activation.
1101 EXPECT_EQ(window1.get(), window_util::GetFocusedWindow());
1102 }
1103
1104 // Tests that if a window is dragged while overview is open, the activation
1105 // of the dragged window does not cancel overview.
TEST_P(OverviewSessionTest,ActivateDraggedWindowNotCancelOverview)1106 TEST_P(OverviewSessionTest, ActivateDraggedWindowNotCancelOverview) {
1107 UpdateDisplay("800x600");
1108 EnterTabletMode();
1109 std::unique_ptr<aura::Window> window1(CreateTestWindow());
1110 window1->SetProperty(aura::client::kAppType,
1111 static_cast<int>(AppType::BROWSER));
1112 std::unique_ptr<aura::Window> window2(CreateTestWindow());
1113 EXPECT_FALSE(InOverviewSession());
1114
1115 // Start drag on |window1|.
1116 std::unique_ptr<WindowResizer> resizer(CreateWindowResizer(
1117 window1.get(), gfx::PointF(), HTCAPTION, ::wm::WINDOW_MOVE_SOURCE_TOUCH));
1118 EXPECT_TRUE(InOverviewSession());
1119
1120 resizer->Drag(gfx::PointF(400, 0), 0);
1121 EXPECT_TRUE(InOverviewSession());
1122
1123 wm::ActivateWindow(window1.get());
1124 EXPECT_TRUE(InOverviewSession());
1125
1126 resizer->CompleteDrag();
1127 EXPECT_FALSE(InOverviewSession());
1128 }
1129
1130 // Tests that activate a non-dragged window during window drag will not cancel
1131 // overview mode.
TEST_P(OverviewSessionTest,ActivateAnotherWindowDuringDragNotCancelOverview)1132 TEST_P(OverviewSessionTest, ActivateAnotherWindowDuringDragNotCancelOverview) {
1133 UpdateDisplay("800x600");
1134 EnterTabletMode();
1135 std::unique_ptr<aura::Window> window1(CreateTestWindow());
1136 window1->SetProperty(aura::client::kAppType,
1137 static_cast<int>(AppType::BROWSER));
1138 std::unique_ptr<aura::Window> window2(CreateTestWindow());
1139 EXPECT_FALSE(InOverviewSession());
1140
1141 // Start drag on |window1|.
1142 wm::ActivateWindow(window1.get());
1143 std::unique_ptr<WindowResizer> resizer(CreateWindowResizer(
1144 window1.get(), gfx::PointF(), HTCAPTION, ::wm::WINDOW_MOVE_SOURCE_TOUCH));
1145 EXPECT_TRUE(InOverviewSession());
1146
1147 // Activate |window2| should not cancel overview mode.
1148 wm::ActivateWindow(window2.get());
1149 EXPECT_FALSE(WindowState::Get(window2.get())->is_dragged());
1150 EXPECT_TRUE(wm::IsActiveWindow(window2.get()));
1151 EXPECT_TRUE(InOverviewSession());
1152 }
1153
1154 // Tests that if an overview item is dragged, the activation of the
1155 // corresponding window does not cancel overview.
TEST_P(OverviewSessionTest,ActivateDraggedOverviewWindowNotCancelOverview)1156 TEST_P(OverviewSessionTest, ActivateDraggedOverviewWindowNotCancelOverview) {
1157 UpdateDisplay("800x600");
1158 EnterTabletMode();
1159 std::unique_ptr<aura::Window> window(CreateTestWindow());
1160 ToggleOverview();
1161 OverviewItem* item = GetOverviewItemForWindow(window.get());
1162 gfx::PointF drag_point = item->target_bounds().CenterPoint();
1163 overview_session()->InitiateDrag(item, drag_point,
1164 /*is_touch_dragging=*/false);
1165 drag_point.Offset(5.f, 0.f);
1166 overview_session()->Drag(item, drag_point);
1167 wm::ActivateWindow(window.get());
1168 EXPECT_TRUE(InOverviewSession());
1169 }
1170
1171 // Tests that if an overview item is dragged, the activation of the window
1172 // corresponding to another overview item does not cancel overview.
TEST_P(OverviewSessionTest,ActivateAnotherOverviewWindowDuringOverviewDragNotCancelOverview)1173 TEST_P(OverviewSessionTest,
1174 ActivateAnotherOverviewWindowDuringOverviewDragNotCancelOverview) {
1175 UpdateDisplay("800x600");
1176 EnterTabletMode();
1177 std::unique_ptr<aura::Window> window1(CreateTestWindow());
1178 std::unique_ptr<aura::Window> window2(CreateTestWindow());
1179 ToggleOverview();
1180 OverviewItem* item1 = GetOverviewItemForWindow(window1.get());
1181 gfx::PointF drag_point = item1->target_bounds().CenterPoint();
1182 overview_session()->InitiateDrag(item1, drag_point,
1183 /*is_touch_dragging=*/false);
1184 drag_point.Offset(5.f, 0.f);
1185 overview_session()->Drag(item1, drag_point);
1186 wm::ActivateWindow(window2.get());
1187 EXPECT_TRUE(InOverviewSession());
1188 }
1189
1190 // Tests that if an overview item is dragged, the activation of a window
1191 // excluded from overview does not cancel overview.
TEST_P(OverviewSessionTest,ActivateWindowExcludedFromOverviewDuringOverviewDragNotCancelOverview)1192 TEST_P(OverviewSessionTest,
1193 ActivateWindowExcludedFromOverviewDuringOverviewDragNotCancelOverview) {
1194 UpdateDisplay("800x600");
1195 EnterTabletMode();
1196 std::unique_ptr<aura::Window> window1(CreateTestWindow());
1197 std::unique_ptr<aura::Window> window2(
1198 CreateTestWindow(gfx::Rect(), aura::client::WINDOW_TYPE_POPUP));
1199 EXPECT_TRUE(window_util::ShouldExcludeForOverview(window2.get()));
1200 ToggleOverview();
1201 OverviewItem* item1 = GetOverviewItemForWindow(window1.get());
1202 gfx::PointF drag_point = item1->target_bounds().CenterPoint();
1203 overview_session()->InitiateDrag(item1, drag_point,
1204 /*is_touch_dragging=*/false);
1205 drag_point.Offset(5.f, 0.f);
1206 overview_session()->Drag(item1, drag_point);
1207 wm::ActivateWindow(window2.get());
1208 EXPECT_TRUE(InOverviewSession());
1209 }
1210
1211 // Tests that exiting overview mode without selecting a window restores focus
1212 // to the previously focused window.
TEST_P(OverviewSessionTest,CancelRestoresFocus)1213 TEST_P(OverviewSessionTest, CancelRestoresFocus) {
1214 std::unique_ptr<aura::Window> window(CreateTestWindow());
1215 wm::ActivateWindow(window.get());
1216 EXPECT_EQ(window.get(), window_util::GetFocusedWindow());
1217
1218 // In overview mode, the overview focus window should be focused.
1219 ToggleOverview();
1220 EXPECT_EQ(overview_session()->GetOverviewFocusWindow(),
1221 window_util::GetFocusedWindow());
1222
1223 // If canceling overview mode, focus should be restored.
1224 ToggleOverview();
1225 EXPECT_EQ(window.get(), window_util::GetFocusedWindow());
1226 }
1227
1228 // Tests that overview mode is exited if the last remaining window is destroyed.
TEST_P(OverviewSessionTest,LastWindowDestroyed)1229 TEST_P(OverviewSessionTest, LastWindowDestroyed) {
1230 std::unique_ptr<aura::Window> window1(CreateTestWindow());
1231 std::unique_ptr<aura::Window> window2(CreateTestWindow());
1232 ToggleOverview();
1233
1234 window1.reset();
1235 window2.reset();
1236 EXPECT_FALSE(InOverviewSession());
1237 }
1238
1239 // Tests that entering overview mode restores a window to its original
1240 // target location.
TEST_P(OverviewSessionTest,QuickReentryRestoresInitialTransform)1241 TEST_P(OverviewSessionTest, QuickReentryRestoresInitialTransform) {
1242 std::unique_ptr<aura::Window> window(CreateTestWindow(gfx::Rect(400, 400)));
1243 gfx::Rect initial_bounds = GetTransformedBounds(window.get());
1244 ToggleOverview();
1245 // Quickly exit and reenter overview mode. The window should still be
1246 // animating when we reenter. We cannot short circuit animations for this but
1247 // we also don't have to wait for them to complete.
1248 {
1249 ui::ScopedAnimationDurationScaleMode test_duration_mode(
1250 ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
1251 ToggleOverview();
1252 ToggleOverview();
1253 }
1254 EXPECT_NE(initial_bounds, GetTransformedTargetBounds(window.get()));
1255 ToggleOverview();
1256 EXPECT_FALSE(InOverviewSession());
1257 EXPECT_EQ(initial_bounds, GetTransformedTargetBounds(window.get()));
1258 }
1259
1260 // Tests that windows with modal child windows are transformed with the modal
1261 // child even though not activatable themselves.
TEST_P(OverviewSessionTest,ModalChild)1262 TEST_P(OverviewSessionTest, ModalChild) {
1263 const gfx::Rect bounds(400, 400);
1264 std::unique_ptr<aura::Window> window(CreateTestWindow(bounds));
1265 std::unique_ptr<aura::Window> child(CreateTestWindow(bounds));
1266 child->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_WINDOW);
1267 ::wm::AddTransientChild(window.get(), child.get());
1268 EXPECT_EQ(window->parent(), child->parent());
1269 ToggleOverview();
1270 EXPECT_TRUE(window->IsVisible());
1271 EXPECT_TRUE(child->IsVisible());
1272 EXPECT_EQ(GetTransformedTargetBounds(child.get()),
1273 GetTransformedTargetBounds(window.get()));
1274 ToggleOverview();
1275 }
1276
1277 // Tests that clicking a modal window's parent activates the modal window in
1278 // overview.
TEST_P(OverviewSessionTest,ClickModalWindowParent)1279 TEST_P(OverviewSessionTest, ClickModalWindowParent) {
1280 std::unique_ptr<aura::Window> window(CreateTestWindow(gfx::Rect(180, 180)));
1281 std::unique_ptr<aura::Window> child(
1282 CreateTestWindow(gfx::Rect(200, 0, 180, 180)));
1283 child->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_WINDOW);
1284 ::wm::AddTransientChild(window.get(), child.get());
1285 EXPECT_FALSE(WindowsOverlapping(window.get(), child.get()));
1286 EXPECT_EQ(window->parent(), child->parent());
1287 ToggleOverview();
1288 // Given that their relative positions are preserved, the windows should still
1289 // not overlap.
1290 EXPECT_FALSE(WindowsOverlapping(window.get(), child.get()));
1291 ClickWindow(window.get());
1292 EXPECT_FALSE(InOverviewSession());
1293
1294 // Clicking on window1 should activate child1.
1295 EXPECT_TRUE(wm::IsActiveWindow(child.get()));
1296 }
1297
1298 // Tests that windows remain on the display they are currently on in overview
1299 // mode, and that the close buttons are on matching displays.
TEST_P(OverviewSessionTest,MultipleDisplays)1300 TEST_P(OverviewSessionTest, MultipleDisplays) {
1301 UpdateDisplay("600x400,600x400");
1302 aura::Window::Windows root_windows = Shell::GetAllRootWindows();
1303 gfx::Rect bounds1(0, 0, 400, 400);
1304 gfx::Rect bounds2(650, 0, 400, 400);
1305
1306 std::unique_ptr<aura::Window> window1(CreateTestWindow(bounds1));
1307 std::unique_ptr<aura::Window> window2(CreateTestWindow(bounds1));
1308 std::unique_ptr<aura::Window> window3(CreateTestWindow(bounds2));
1309 std::unique_ptr<aura::Window> window4(CreateTestWindow(bounds2));
1310 EXPECT_EQ(root_windows[0], window1->GetRootWindow());
1311 EXPECT_EQ(root_windows[0], window2->GetRootWindow());
1312 EXPECT_EQ(root_windows[1], window3->GetRootWindow());
1313 EXPECT_EQ(root_windows[1], window4->GetRootWindow());
1314
1315 // In overview mode, each window remains in the same root window.
1316 ToggleOverview();
1317 EXPECT_EQ(root_windows[0], window1->GetRootWindow());
1318 EXPECT_EQ(root_windows[0], window2->GetRootWindow());
1319 EXPECT_EQ(root_windows[1], window3->GetRootWindow());
1320 EXPECT_EQ(root_windows[1], window4->GetRootWindow());
1321
1322 // Window indices are based on top-down order. The reverse of our creation.
1323 CheckWindowAndCloseButtonInScreen(window1.get(),
1324 GetOverviewItemForWindow(window1.get()));
1325 CheckWindowAndCloseButtonInScreen(window2.get(),
1326 GetOverviewItemForWindow(window2.get()));
1327 CheckWindowAndCloseButtonInScreen(window3.get(),
1328 GetOverviewItemForWindow(window3.get()));
1329 CheckWindowAndCloseButtonInScreen(window4.get(),
1330 GetOverviewItemForWindow(window4.get()));
1331 }
1332
1333 // Tests shutting down during overview.
TEST_P(OverviewSessionTest,Shutdown)1334 TEST_P(OverviewSessionTest, Shutdown) {
1335 // These windows will be deleted when the test exits and the Shell instance
1336 // is shut down.
1337 std::unique_ptr<aura::Window> window1(CreateTestWindow());
1338 std::unique_ptr<aura::Window> window2(CreateTestWindow());
1339
1340 wm::ActivateWindow(window2.get());
1341 wm::ActivateWindow(window1.get());
1342
1343 ToggleOverview();
1344 }
1345
1346 // Tests adding a display during overview.
TEST_P(OverviewSessionTest,AddDisplay)1347 TEST_P(OverviewSessionTest, AddDisplay) {
1348 UpdateDisplay("400x400");
1349 ToggleOverview();
1350 EXPECT_TRUE(InOverviewSession());
1351 UpdateDisplay("400x400,400x400");
1352 EXPECT_FALSE(InOverviewSession());
1353 }
1354
1355 // Tests removing a display during overview.
TEST_P(OverviewSessionTest,RemoveDisplay)1356 TEST_P(OverviewSessionTest, RemoveDisplay) {
1357 UpdateDisplay("400x400,400x400");
1358 std::unique_ptr<aura::Window> window1(CreateTestWindow(gfx::Rect(100, 100)));
1359 std::unique_ptr<aura::Window> window2(
1360 CreateTestWindow(gfx::Rect(450, 0, 100, 100)));
1361
1362 aura::Window::Windows root_windows = Shell::GetAllRootWindows();
1363 EXPECT_EQ(root_windows[0], window1->GetRootWindow());
1364 EXPECT_EQ(root_windows[1], window2->GetRootWindow());
1365
1366 wm::ActivateWindow(window2.get());
1367 wm::ActivateWindow(window1.get());
1368
1369 ToggleOverview();
1370 EXPECT_TRUE(InOverviewSession());
1371 UpdateDisplay("400x400");
1372 EXPECT_FALSE(InOverviewSession());
1373 }
1374
1375 // Tests removing a display during overview with NON_ZERO_DURATION animation.
TEST_P(OverviewSessionTest,RemoveDisplayWithAnimation)1376 TEST_P(OverviewSessionTest, RemoveDisplayWithAnimation) {
1377 UpdateDisplay("400x400,400x400");
1378 std::unique_ptr<aura::Window> window1(CreateTestWindow(gfx::Rect(100, 100)));
1379 std::unique_ptr<aura::Window> window2(
1380 CreateTestWindow(gfx::Rect(450, 0, 100, 100)));
1381
1382 aura::Window::Windows root_windows = Shell::GetAllRootWindows();
1383 EXPECT_EQ(root_windows[0], window1->GetRootWindow());
1384 EXPECT_EQ(root_windows[1], window2->GetRootWindow());
1385
1386 wm::ActivateWindow(window2.get());
1387 wm::ActivateWindow(window1.get());
1388
1389 ToggleOverview();
1390 EXPECT_TRUE(InOverviewSession());
1391
1392 ui::ScopedAnimationDurationScaleMode test_duration_mode(
1393 ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
1394 UpdateDisplay("400x400");
1395 EXPECT_FALSE(InOverviewSession());
1396 }
1397
1398 // Tests that tab key does not cause crash if pressed just after overview
1399 // session exits.
TEST_P(OverviewSessionTest,NoCrashOnTabAfterExit)1400 TEST_P(OverviewSessionTest, NoCrashOnTabAfterExit) {
1401 std::unique_ptr<aura::Window> window = CreateTestWindow();
1402 wm::ActivateWindow(window.get());
1403
1404 ToggleOverview();
1405 EXPECT_TRUE(InOverviewSession());
1406
1407 ToggleOverview();
1408 SendKey(ui::VKEY_TAB);
1409 EXPECT_FALSE(InOverviewSession());
1410 }
1411
1412 // Tests that tab key does not cause crash if pressed just after overview
1413 // session exits, and a child window was active before session start.
TEST_P(OverviewSessionTest,NoCrashOnTabAfterExitWithChildWindowInitiallyFocused)1414 TEST_P(OverviewSessionTest,
1415 NoCrashOnTabAfterExitWithChildWindowInitiallyFocused) {
1416 std::unique_ptr<aura::Window> window = CreateTestWindow();
1417 std::unique_ptr<aura::Window> child_window = CreateChildWindow(window.get());
1418
1419 wm::ActivateWindow(child_window.get());
1420
1421 ToggleOverview();
1422 EXPECT_TRUE(InOverviewSession());
1423
1424 ToggleOverview();
1425 SendKey(ui::VKEY_TAB);
1426 EXPECT_FALSE(InOverviewSession());
1427 }
1428
1429 // Tests that tab key does not cause crash if pressed just after overview
1430 // session exits when no windows existed before starting overview session.
TEST_P(OverviewSessionTest,NoCrashOnTabAfterExitWithNoWindows)1431 TEST_P(OverviewSessionTest, NoCrashOnTabAfterExitWithNoWindows) {
1432 ToggleOverview();
1433 EXPECT_TRUE(InOverviewSession());
1434
1435 ToggleOverview();
1436 SendKey(ui::VKEY_TAB);
1437 EXPECT_FALSE(InOverviewSession());
1438 }
1439
1440 // Tests that dragging a window from overview creates a drop target on the same
1441 // display.
TEST_P(OverviewSessionTest,DropTargetOnCorrectDisplayForDraggingFromOverview)1442 TEST_P(OverviewSessionTest, DropTargetOnCorrectDisplayForDraggingFromOverview) {
1443 UpdateDisplay("600x600,600x600");
1444 EnterTabletMode();
1445 // DisplayConfigurationObserver enables mirror mode when tablet mode is
1446 // enabled. Disable mirror mode to test multiple displays.
1447 display_manager()->SetMirrorMode(display::MirrorMode::kOff, base::nullopt);
1448 base::RunLoop().RunUntilIdle();
1449
1450 const aura::Window::Windows root_windows = Shell::Get()->GetAllRootWindows();
1451 ASSERT_EQ(2u, root_windows.size());
1452
1453 std::unique_ptr<aura::Window> primary_screen_window =
1454 CreateTestWindow(gfx::Rect(0, 0, 600, 600));
1455 ASSERT_EQ(root_windows[0], primary_screen_window->GetRootWindow());
1456 std::unique_ptr<aura::Window> secondary_screen_window =
1457 CreateTestWindow(gfx::Rect(600, 0, 600, 600));
1458 ASSERT_EQ(root_windows[1], secondary_screen_window->GetRootWindow());
1459
1460 ToggleOverview();
1461 OverviewItem* primary_screen_item =
1462 GetOverviewItemForWindow(primary_screen_window.get());
1463 OverviewItem* secondary_screen_item =
1464 GetOverviewItemForWindow(secondary_screen_window.get());
1465
1466 EXPECT_FALSE(GetDropTarget(0));
1467 EXPECT_FALSE(GetDropTarget(1));
1468 gfx::PointF drag_point = primary_screen_item->target_bounds().CenterPoint();
1469 overview_session()->InitiateDrag(primary_screen_item, drag_point,
1470 /*is_touch_dragging=*/true);
1471 EXPECT_FALSE(GetDropTarget(0));
1472 EXPECT_FALSE(GetDropTarget(1));
1473 drag_point.Offset(5.f, 0.f);
1474 overview_session()->Drag(primary_screen_item, drag_point);
1475 EXPECT_FALSE(GetDropTarget(1));
1476 ASSERT_TRUE(GetDropTarget(0));
1477 EXPECT_EQ(root_windows[0], GetDropTarget(0)->root_window());
1478 overview_session()->CompleteDrag(primary_screen_item, drag_point);
1479 EXPECT_FALSE(GetDropTarget(0));
1480 EXPECT_FALSE(GetDropTarget(1));
1481 drag_point = secondary_screen_item->target_bounds().CenterPoint();
1482 overview_session()->InitiateDrag(secondary_screen_item, drag_point,
1483 /*is_touch_dragging=*/true);
1484 EXPECT_FALSE(GetDropTarget(0));
1485 EXPECT_FALSE(GetDropTarget(1));
1486 drag_point.Offset(5.f, 0.f);
1487 overview_session()->Drag(secondary_screen_item, drag_point);
1488 EXPECT_FALSE(GetDropTarget(0));
1489 ASSERT_TRUE(GetDropTarget(1));
1490 EXPECT_EQ(root_windows[1], GetDropTarget(1)->root_window());
1491 overview_session()->CompleteDrag(secondary_screen_item, drag_point);
1492 EXPECT_FALSE(GetDropTarget(0));
1493 EXPECT_FALSE(GetDropTarget(1));
1494 }
1495
1496 // Tests that the drop target is removed if a window is destroyed while being
1497 // dragged from the top.
TEST_P(OverviewSessionTest,DropTargetRemovedIfWindowDraggedFromTopIsDestroyed)1498 TEST_P(OverviewSessionTest,
1499 DropTargetRemovedIfWindowDraggedFromTopIsDestroyed) {
1500 EnterTabletMode();
1501 std::unique_ptr<aura::Window> window = CreateTestWindow();
1502 std::unique_ptr<aura::Window> window2 = CreateTestWindow();
1503 window->SetProperty(aura::client::kAppType,
1504 static_cast<int>(AppType::BROWSER));
1505 std::unique_ptr<WindowResizer> resizer =
1506 CreateWindowResizer(window.get(), gfx::PointF(400, 0), HTCAPTION,
1507 ::wm::WINDOW_MOVE_SOURCE_TOUCH);
1508 ASSERT_TRUE(InOverviewSession());
1509 EXPECT_TRUE(GetDropTarget(0));
1510 resizer.reset();
1511 window.reset();
1512 ASSERT_TRUE(InOverviewSession());
1513 EXPECT_FALSE(GetDropTarget(0));
1514 }
1515
1516 namespace {
1517
1518 // A simple window delegate that returns the specified hit-test code when
1519 // requested and applies a minimum size constraint if there is one.
1520 class TestDragWindowDelegate : public aura::test::TestWindowDelegate {
1521 public:
TestDragWindowDelegate()1522 TestDragWindowDelegate() { set_window_component(HTCAPTION); }
1523 ~TestDragWindowDelegate() override = default;
1524
1525 private:
1526 // aura::Test::TestWindowDelegate:
OnWindowDestroyed(aura::Window * window)1527 void OnWindowDestroyed(aura::Window* window) override { delete this; }
1528
1529 DISALLOW_COPY_AND_ASSIGN(TestDragWindowDelegate);
1530 };
1531
1532 } // namespace
1533
1534 // Tests that toggling overview on and off does not cancel drag.
TEST_P(OverviewSessionTest,DragDropInProgress)1535 TEST_P(OverviewSessionTest, DragDropInProgress) {
1536 std::unique_ptr<aura::Window> window(CreateTestWindowInShellWithDelegate(
1537 new TestDragWindowDelegate(), -1, gfx::Rect(100, 100)));
1538
1539 GetEventGenerator()->set_current_screen_location(
1540 window->GetBoundsInScreen().CenterPoint());
1541 GetEventGenerator()->PressLeftButton();
1542 GetEventGenerator()->MoveMouseBy(10, 10);
1543 EXPECT_EQ(gfx::Rect(10, 10, 100, 100), window->bounds());
1544
1545 ToggleOverview();
1546 ASSERT_TRUE(InOverviewSession());
1547
1548 GetEventGenerator()->MoveMouseBy(10, 10);
1549
1550 ToggleOverview();
1551 ASSERT_FALSE(InOverviewSession());
1552
1553 GetEventGenerator()->MoveMouseBy(10, 10);
1554 GetEventGenerator()->ReleaseLeftButton();
1555 base::RunLoop().RunUntilIdle();
1556 EXPECT_EQ(gfx::Rect(30, 30, 100, 100), window->bounds());
1557 }
1558
1559 // Tests that toggling overview on removes any resize shadows that may have been
1560 // present.
TEST_P(OverviewSessionTest,DragWindowShadow)1561 TEST_P(OverviewSessionTest, DragWindowShadow) {
1562 std::unique_ptr<aura::Window> window(CreateTestWindow(gfx::Rect(100, 100)));
1563 wm::ActivateWindow(window.get());
1564 Shell::Get()->resize_shadow_controller()->ShowShadow(window.get(), HTTOP);
1565
1566 ToggleOverview();
1567 ResizeShadow* shadow =
1568 Shell::Get()->resize_shadow_controller()->GetShadowForWindowForTest(
1569 window.get());
1570 EXPECT_FALSE(shadow);
1571 }
1572
1573 // Test that a label is created under the window on entering overview mode.
TEST_P(OverviewSessionTest,CreateLabelUnderWindow)1574 TEST_P(OverviewSessionTest, CreateLabelUnderWindow) {
1575 std::unique_ptr<aura::Window> window(CreateTestWindow(gfx::Rect(300, 500)));
1576 const base::string16 window_title = base::UTF8ToUTF16("My window");
1577 window->SetTitle(window_title);
1578 ToggleOverview();
1579 OverviewItem* window_item = GetOverviewItemsForRoot(0).back().get();
1580 views::Label* label = GetLabelView(window_item);
1581 ASSERT_TRUE(label);
1582
1583 // Verify the label matches the window title.
1584 EXPECT_EQ(window_title, label->GetText());
1585
1586 // Update the window title and check that the label is updated, too.
1587 const base::string16 updated_title = base::UTF8ToUTF16("Updated title");
1588 window->SetTitle(updated_title);
1589 EXPECT_EQ(updated_title, label->GetText());
1590
1591 // Labels are located based on target_bounds, not the actual window item
1592 // bounds.
1593 gfx::RectF label_bounds(label->GetWidget()->GetWindowBoundsInScreen());
1594 EXPECT_EQ(label_bounds, window_item->target_bounds());
1595 }
1596
1597 // Tests that overview updates the window positions if the display orientation
1598 // changes.
TEST_P(OverviewSessionTest,DisplayOrientationChanged)1599 TEST_P(OverviewSessionTest, DisplayOrientationChanged) {
1600 aura::Window* root_window = Shell::Get()->GetPrimaryRootWindow();
1601 UpdateDisplay("600x200");
1602 EXPECT_EQ(gfx::Rect(600, 200), root_window->bounds());
1603 std::vector<std::unique_ptr<aura::Window>> windows;
1604 for (int i = 0; i < 3; i++) {
1605 windows.push_back(
1606 std::unique_ptr<aura::Window>(CreateTestWindow(gfx::Rect(150, 150))));
1607 }
1608
1609 ToggleOverview();
1610 for (const auto& window : windows) {
1611 EXPECT_TRUE(root_window->bounds().Contains(
1612 GetTransformedTargetBounds(window.get())));
1613 }
1614
1615 // Rotate the display, windows should be repositioned to be within the screen
1616 // bounds.
1617 UpdateDisplay("600x200/r");
1618 EXPECT_EQ(gfx::Rect(200, 600), root_window->bounds());
1619 for (const auto& window : windows) {
1620 EXPECT_TRUE(root_window->bounds().Contains(
1621 GetTransformedTargetBounds(window.get())));
1622 }
1623 }
1624
TEST_P(OverviewSessionTest,AcceleratorInOverviewSession)1625 TEST_P(OverviewSessionTest, AcceleratorInOverviewSession) {
1626 ToggleOverview();
1627 auto* accelerator_controller = Shell::Get()->accelerator_controller();
1628 auto* ewh = accelerator_controller->GetExitWarningHandlerForTest();
1629 ASSERT_TRUE(ewh);
1630 StubForTest(ewh);
1631 EXPECT_FALSE(is_ui_shown(ewh));
1632
1633 ui::test::EventGenerator event_generator(Shell::GetPrimaryRootWindow());
1634 event_generator.PressKey(ui::VKEY_Q, ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN);
1635 event_generator.ReleaseKey(ui::VKEY_Q,
1636 ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN);
1637
1638 EXPECT_TRUE(is_ui_shown(ewh));
1639 }
1640
1641 // Tests hitting the escape and back keys exits overview mode.
TEST_P(OverviewSessionTest,ExitOverviewWithKey)1642 TEST_P(OverviewSessionTest, ExitOverviewWithKey) {
1643 std::unique_ptr<aura::Window> window(CreateTestWindow());
1644
1645 ToggleOverview();
1646 ASSERT_TRUE(overview_controller()->InOverviewSession());
1647 SendKey(ui::VKEY_ESCAPE);
1648 EXPECT_FALSE(overview_controller()->InOverviewSession());
1649
1650 ToggleOverview();
1651 ASSERT_TRUE(overview_controller()->InOverviewSession());
1652 SendKey(ui::VKEY_BROWSER_BACK);
1653 EXPECT_FALSE(overview_controller()->InOverviewSession());
1654
1655 // Tests that in tablet mode, if we snap the only overview window, we cannot
1656 // exit overview mode.
1657 EnterTabletMode();
1658 ToggleOverview();
1659 ASSERT_TRUE(overview_controller()->InOverviewSession());
1660 split_view_controller()->SnapWindow(window.get(), SplitViewController::LEFT);
1661 ASSERT_TRUE(overview_controller()->InOverviewSession());
1662 SendKey(ui::VKEY_ESCAPE);
1663 EXPECT_TRUE(overview_controller()->InOverviewSession());
1664 SendKey(ui::VKEY_BROWSER_BACK);
1665 EXPECT_TRUE(overview_controller()->InOverviewSession());
1666 }
1667
1668 // Regression test for clusterfuzz crash. https://crbug.com/920568
TEST_P(OverviewSessionTest,TypeThenPressEscapeTwice)1669 TEST_P(OverviewSessionTest, TypeThenPressEscapeTwice) {
1670 std::unique_ptr<aura::Window> window(CreateTestWindow());
1671 ToggleOverview();
1672
1673 // Type some characters.
1674 SendKey(ui::VKEY_A);
1675 SendKey(ui::VKEY_B);
1676 SendKey(ui::VKEY_C);
1677 EXPECT_TRUE(overview_session()->GetOverviewFocusWindow());
1678
1679 // Pressing escape twice should not crash.
1680 SendKey(ui::VKEY_ESCAPE);
1681 SendKey(ui::VKEY_ESCAPE);
1682 }
1683
TEST_P(OverviewSessionTest,CancelOverviewOnMouseClick)1684 TEST_P(OverviewSessionTest, CancelOverviewOnMouseClick) {
1685 std::unique_ptr<aura::Window> window(
1686 CreateTestWindow(gfx::Rect(10, 10, 100, 100)));
1687 // Move mouse to point in the background page. Sending an event here will pass
1688 // it to the WallpaperController in both regular and overview mode.
1689 GetEventGenerator()->MoveMouseTo(gfx::Point(0, 0));
1690
1691 // Clicking on the background page while not in overview should not toggle
1692 // overview.
1693 GetEventGenerator()->ClickLeftButton();
1694 EXPECT_FALSE(InOverviewSession());
1695
1696 // Switch to overview mode. Clicking should now exit overview mode.
1697 ToggleOverview();
1698 ASSERT_TRUE(InOverviewSession());
1699 // Choose a point that doesn't intersect with the window or the desks bar.
1700 const gfx::Point point_in_background_page = GetGridBounds().CenterPoint();
1701 GetEventGenerator()->MoveMouseTo(point_in_background_page);
1702 GetEventGenerator()->ClickLeftButton();
1703 EXPECT_FALSE(InOverviewSession());
1704 }
1705
1706 // Tests tapping on the desktop itself to cancel overview mode.
TEST_P(OverviewSessionTest,CancelOverviewOnTap)1707 TEST_P(OverviewSessionTest, CancelOverviewOnTap) {
1708 std::unique_ptr<aura::Window> window(
1709 CreateTestWindow(gfx::Rect(10, 10, 100, 100)));
1710
1711 // Tapping on the background page while not in overview should not toggle
1712 // overview.
1713 GetEventGenerator()->GestureTapAt(gfx::Point(0, 0));
1714 EXPECT_FALSE(InOverviewSession());
1715
1716 // Switch to overview mode. Tapping should now exit overview mode.
1717 ToggleOverview();
1718 ASSERT_TRUE(InOverviewSession());
1719 // A point that doesn't intersect with the window nor the desks bar. This
1720 // causes events located at the point to be passed to WallpaperController, and
1721 // not the window.
1722 const gfx::Point point_in_background_page = GetGridBounds().CenterPoint();
1723 GetEventGenerator()->GestureTapAt(point_in_background_page);
1724 EXPECT_FALSE(InOverviewSession());
1725 }
1726
1727 // Start dragging a window and activate overview mode. This test should not
1728 // crash or DCHECK inside aura::Window::StackChildRelativeTo().
TEST_P(OverviewSessionTest,OverviewWhileDragging)1729 TEST_P(OverviewSessionTest, OverviewWhileDragging) {
1730 std::unique_ptr<aura::Window> window(CreateTestWindow());
1731 std::unique_ptr<WindowResizer> resizer(CreateWindowResizer(
1732 window.get(), gfx::PointF(), HTCAPTION, ::wm::WINDOW_MOVE_SOURCE_MOUSE));
1733 ASSERT_TRUE(resizer.get());
1734 gfx::PointF location = resizer->GetInitialLocation();
1735 location.Offset(20, 20);
1736 resizer->Drag(location, 0);
1737 ToggleOverview();
1738 resizer->RevertDrag();
1739 }
1740
1741 // Verify that the overview no windows indicator appears when entering overview
1742 // mode with no windows.
TEST_P(OverviewSessionTest,NoWindowsIndicator)1743 TEST_P(OverviewSessionTest, NoWindowsIndicator) {
1744 // Verify that by entering overview mode without windows, the no items
1745 // indicator appears.
1746 ToggleOverview();
1747 ASSERT_TRUE(overview_session());
1748 ASSERT_EQ(0u, GetOverviewItemsForRoot(0).size());
1749 EXPECT_TRUE(overview_session()->no_windows_widget_for_testing());
1750 }
1751
1752 // Verify that the overview no windows indicator position is as expected.
TEST_P(OverviewSessionTest,NoWindowsIndicatorPosition)1753 TEST_P(OverviewSessionTest, NoWindowsIndicatorPosition) {
1754 UpdateDisplay("400x300");
1755
1756 ToggleOverview();
1757 ASSERT_TRUE(overview_session());
1758 RoundedLabelWidget* no_windows_widget =
1759 overview_session()->no_windows_widget_for_testing();
1760 ASSERT_TRUE(no_windows_widget);
1761
1762 // Verify that originally the label is in the center of the workspace.
1763 // Midpoint of height minus shelf.
1764 int expected_y = (300 - ShelfConfig::Get()->shelf_size()) / 2;
1765 EXPECT_EQ(gfx::Point(200, expected_y),
1766 no_windows_widget->GetWindowBoundsInScreen().CenterPoint());
1767
1768 // Verify that after rotating the display, the label is centered in the
1769 // workspace 300x(400-shelf).
1770 display::Screen* screen = display::Screen::GetScreen();
1771 const display::Display& display = screen->GetPrimaryDisplay();
1772 display_manager()->SetDisplayRotation(
1773 display.id(), display::Display::ROTATE_90,
1774 display::Display::RotationSource::ACTIVE);
1775 expected_y = (400 - ShelfConfig::Get()->shelf_size()) / 2;
1776 EXPECT_EQ(gfx::Point(150, (400 - ShelfConfig::Get()->shelf_size()) / 2),
1777 no_windows_widget->GetWindowBoundsInScreen().CenterPoint());
1778 }
1779
1780 // Tests that toggling overview on removes any resize shadows that may have been
1781 // present.
TEST_P(OverviewSessionTest,DragMinimizedWindowHasStableSize)1782 TEST_P(OverviewSessionTest, DragMinimizedWindowHasStableSize) {
1783 UpdateDisplay(base::StringPrintf("1920x1200*%s", display::kDsfStr_1_777));
1784 EnterTabletMode();
1785 std::unique_ptr<aura::Window> window(CreateTestWindow());
1786
1787 WindowState::Get(window.get())->Minimize();
1788 ToggleOverview();
1789 OverviewItem* overview_item = GetOverviewItemForWindow(window.get());
1790 auto* widget = overview_item->item_widget();
1791
1792 gfx::Rect workarea =
1793 display::Screen::GetScreen()->GetPrimaryDisplay().work_area();
1794
1795 gfx::PointF drag_point(workarea.CenterPoint());
1796 overview_session()->InitiateDrag(overview_item, drag_point,
1797 /*is_touch_dragging=*/true);
1798 gfx::Size target_size =
1799 GetTransformedTargetBounds(widget->GetNativeWindow()).size();
1800
1801 drag_point.Offset(0, 10.5f);
1802 overview_session()->Drag(overview_item, drag_point);
1803 gfx::Size new_target_size =
1804 GetTransformedTargetBounds(widget->GetNativeWindow()).size();
1805 EXPECT_EQ(target_size, new_target_size);
1806 target_size = new_target_size;
1807
1808 drag_point.Offset(0, 10.5f);
1809 overview_session()->Drag(overview_item, drag_point);
1810 EXPECT_EQ(target_size,
1811 GetTransformedTargetBounds(widget->GetNativeWindow()).size());
1812
1813 overview_session()->CompleteDrag(overview_item, drag_point);
1814 }
1815
1816 // Tests that the bounds of the grid do not intersect the shelf or its hotseat.
TEST_P(OverviewSessionTest,OverviewGridBounds)1817 TEST_P(OverviewSessionTest, OverviewGridBounds) {
1818 EnterTabletMode();
1819 std::unique_ptr<aura::Window> window(CreateTestWindow());
1820
1821 ToggleOverview();
1822 ASSERT_TRUE(overview_session());
1823
1824 Shelf* shelf = Shelf::ForWindow(Shell::GetPrimaryRootWindow());
1825 const gfx::Rect shelf_bounds = shelf->GetIdealBounds();
1826 const gfx::Rect hotseat_bounds =
1827 shelf->hotseat_widget()->GetWindowBoundsInScreen();
1828 EXPECT_FALSE(GetGridBounds().Intersects(shelf_bounds));
1829 EXPECT_FALSE(GetGridBounds().Intersects(hotseat_bounds));
1830 }
1831
TEST_P(OverviewSessionTest,NoWindowsIndicatorPositionSplitview)1832 TEST_P(OverviewSessionTest, NoWindowsIndicatorPositionSplitview) {
1833 UpdateDisplay("400x300");
1834 EnterTabletMode();
1835 std::unique_ptr<aura::Window> window(CreateTestWindow());
1836
1837 ToggleOverview();
1838 ASSERT_TRUE(overview_session());
1839 RoundedLabelWidget* no_windows_widget =
1840 overview_session()->no_windows_widget_for_testing();
1841 EXPECT_FALSE(no_windows_widget);
1842
1843 // Tests that when snapping a window to the left in splitview, the no windows
1844 // indicator shows up in the middle of the right side of the screen.
1845 split_view_controller()->SnapWindow(window.get(), SplitViewController::LEFT);
1846 no_windows_widget = overview_session()->no_windows_widget_for_testing();
1847 ASSERT_TRUE(no_windows_widget);
1848
1849 // There is a 8dp divider in splitview, the indicator should take that into
1850 // account.
1851 const int bounds_left = 200 + 4;
1852 int expected_x = bounds_left + (400 - (bounds_left)) / 2;
1853 const int workarea_bottom_inset = ShelfConfig::Get()->in_app_shelf_size();
1854 const int expected_y = (300 - workarea_bottom_inset) / 2;
1855 EXPECT_EQ(gfx::Point(expected_x, expected_y),
1856 no_windows_widget->GetWindowBoundsInScreen().CenterPoint());
1857
1858 // Tests that when snapping a window to the right in splitview, the no windows
1859 // indicator shows up in the middle of the left side of the screen.
1860 split_view_controller()->SnapWindow(window.get(), SplitViewController::RIGHT);
1861 expected_x = /*bounds_right=*/(200 - 4) / 2;
1862 EXPECT_EQ(gfx::Point(expected_x, expected_y),
1863 no_windows_widget->GetWindowBoundsInScreen().CenterPoint());
1864 }
1865
1866 // Tests that the no windows indicator shows properly after adding an item.
TEST_P(OverviewSessionTest,NoWindowsIndicatorAddItem)1867 TEST_P(OverviewSessionTest, NoWindowsIndicatorAddItem) {
1868 EnterTabletMode();
1869 std::unique_ptr<aura::Window> window(CreateTestWindow());
1870
1871 ToggleOverview();
1872 split_view_controller()->SnapWindow(window.get(), SplitViewController::LEFT);
1873 EXPECT_TRUE(overview_session()->no_windows_widget_for_testing());
1874
1875 overview_session()->AddItem(window.get(), /*reposition=*/true,
1876 /*animate=*/false, /*ignored_items=*/{},
1877 /*index=*/0u);
1878 EXPECT_FALSE(overview_session()->no_windows_widget_for_testing());
1879 }
1880
1881 // Verify that when opening overview mode with multiple displays, the no items
1882 // indicator on the primary grid if there are no windows.
TEST_P(OverviewSessionTest,NoWindowsIndicatorPositionMultiDisplay)1883 TEST_P(OverviewSessionTest, NoWindowsIndicatorPositionMultiDisplay) {
1884 UpdateDisplay("400x400,400x400,400x400");
1885
1886 // Enter overview mode. Verify that the no windows indicator is located on the
1887 // primary display.
1888 ToggleOverview();
1889 ASSERT_TRUE(overview_session());
1890 RoundedLabelWidget* no_windows_widget =
1891 overview_session()->no_windows_widget_for_testing();
1892 const int expected_y = (400 - ShelfConfig::Get()->shelf_size()) / 2;
1893 EXPECT_EQ(gfx::Point(200, expected_y),
1894 no_windows_widget->GetWindowBoundsInScreen().CenterPoint());
1895 }
1896
1897 // Tests that we do not exit overview mode until all the grids are empty.
TEST_P(OverviewSessionTest,ExitOverviewWhenAllGridsEmpty)1898 TEST_P(OverviewSessionTest, ExitOverviewWhenAllGridsEmpty) {
1899 UpdateDisplay("400x400,400x400,400x400");
1900
1901 // Create two windows with widgets (widgets are needed to close the windows
1902 // later in the test), one each on the first two monitors.
1903 aura::Window::Windows root_windows = Shell::GetAllRootWindows();
1904 std::unique_ptr<views::Widget> widget1(CreateTestWidget());
1905 std::unique_ptr<views::Widget> widget2(CreateTestWidget());
1906 aura::Window* window1 = widget1->GetNativeWindow();
1907 aura::Window* window2 = widget2->GetNativeWindow();
1908 ASSERT_TRUE(
1909 window_util::MoveWindowToDisplay(window2, GetSecondaryDisplay().id()));
1910 ASSERT_EQ(root_windows[0], window1->GetRootWindow());
1911 ASSERT_EQ(root_windows[1], window2->GetRootWindow());
1912
1913 // Enter overview mode. Verify that the no windows indicator is not visible on
1914 // any display.
1915 ToggleOverview();
1916 auto& grids = overview_session()->grid_list();
1917 ASSERT_TRUE(overview_session());
1918 ASSERT_EQ(3u, grids.size());
1919 EXPECT_FALSE(overview_session()->no_windows_widget_for_testing());
1920
1921 OverviewItem* item1 = GetOverviewItemForWindow(window1);
1922 OverviewItem* item2 = GetOverviewItemForWindow(window2);
1923 ASSERT_TRUE(item1 && item2);
1924
1925 // Close |item2|. Verify that we are still in overview mode because |window1|
1926 // is still open. The non primary root grids are empty however.
1927 item2->CloseWindow();
1928 base::RunLoop().RunUntilIdle();
1929 ASSERT_TRUE(overview_session());
1930 ASSERT_EQ(3u, grids.size());
1931 EXPECT_FALSE(grids[0]->empty());
1932 EXPECT_TRUE(grids[1]->empty());
1933 EXPECT_TRUE(grids[2]->empty());
1934 EXPECT_FALSE(overview_session()->no_windows_widget_for_testing());
1935
1936 // Close |item1|. Verify that since no windows are open, we exit overview
1937 // mode.
1938 item1->CloseWindow();
1939 base::RunLoop().RunUntilIdle();
1940 EXPECT_FALSE(overview_session());
1941 }
1942
1943 // Tests window list animation states are correctly updated.
TEST_P(OverviewSessionTest,SetWindowListAnimationStates)1944 TEST_P(OverviewSessionTest, SetWindowListAnimationStates) {
1945 std::unique_ptr<aura::Window> window1(CreateTestWindow());
1946 std::unique_ptr<aura::Window> window2(CreateTestWindow());
1947 std::unique_ptr<aura::Window> window3(CreateTestWindow());
1948 wm::ActivateWindow(window3.get());
1949 wm::ActivateWindow(window2.get());
1950 wm::ActivateWindow(window1.get());
1951
1952 EXPECT_FALSE(WindowState::Get(window1.get())->IsFullscreen());
1953 EXPECT_FALSE(WindowState::Get(window2.get())->IsFullscreen());
1954 EXPECT_FALSE(WindowState::Get(window3.get())->IsFullscreen());
1955
1956 const WMEvent toggle_fullscreen_event(WM_EVENT_TOGGLE_FULLSCREEN);
1957 WindowState::Get(window2.get())->OnWMEvent(&toggle_fullscreen_event);
1958 WindowState::Get(window3.get())->OnWMEvent(&toggle_fullscreen_event);
1959 EXPECT_FALSE(WindowState::Get(window1.get())->IsFullscreen());
1960 EXPECT_TRUE(WindowState::Get(window2.get())->IsFullscreen());
1961 EXPECT_TRUE(WindowState::Get(window3.get())->IsFullscreen());
1962
1963 ui::ScopedAnimationDurationScaleMode test_duration_mode(
1964 ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
1965 // Enter overview.
1966 ToggleOverview();
1967 EXPECT_TRUE(window1->layer()->GetAnimator()->is_animating());
1968 EXPECT_TRUE(window2->layer()->GetAnimator()->is_animating());
1969 EXPECT_FALSE(window3->layer()->GetAnimator()->is_animating());
1970
1971 ToggleOverview();
1972 }
1973
1974 // Tests window list animation states are correctly updated with selected
1975 // window.
TEST_P(OverviewSessionTest,SetWindowListAnimationStatesWithSelectedWindow)1976 TEST_P(OverviewSessionTest, SetWindowListAnimationStatesWithSelectedWindow) {
1977 std::unique_ptr<aura::Window> window1(CreateTestWindow());
1978 std::unique_ptr<aura::Window> window2(CreateTestWindow());
1979 std::unique_ptr<aura::Window> window3(CreateTestWindow());
1980 wm::ActivateWindow(window3.get());
1981 wm::ActivateWindow(window2.get());
1982 wm::ActivateWindow(window1.get());
1983
1984 EXPECT_FALSE(WindowState::Get(window1.get())->IsFullscreen());
1985 EXPECT_FALSE(WindowState::Get(window2.get())->IsFullscreen());
1986 EXPECT_FALSE(WindowState::Get(window3.get())->IsFullscreen());
1987
1988 const WMEvent toggle_fullscreen_event(WM_EVENT_TOGGLE_FULLSCREEN);
1989 WindowState::Get(window2.get())->OnWMEvent(&toggle_fullscreen_event);
1990 WindowState::Get(window3.get())->OnWMEvent(&toggle_fullscreen_event);
1991 EXPECT_FALSE(WindowState::Get(window1.get())->IsFullscreen());
1992 EXPECT_TRUE(WindowState::Get(window2.get())->IsFullscreen());
1993 EXPECT_TRUE(WindowState::Get(window3.get())->IsFullscreen());
1994
1995 // Enter overview.
1996 ToggleOverview();
1997
1998 ui::ScopedAnimationDurationScaleMode test_duration_mode(
1999 ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
2000 // Click on |window3| to activate it and exit overview.
2001 // Should only set |should_animate_when_exiting_| and
2002 // |should_be_observed_when_exiting_| on window 3.
2003 TweenTester tester1(window1.get());
2004 TweenTester tester2(window2.get());
2005 TweenTester tester3(window3.get());
2006 ClickWindow(window3.get());
2007 EXPECT_EQ(gfx::Tween::ZERO, tester1.tween_type());
2008 EXPECT_EQ(gfx::Tween::ZERO, tester2.tween_type());
2009 EXPECT_EQ(gfx::Tween::EASE_OUT, tester3.tween_type());
2010 }
2011
2012 // Tests OverviewWindowAnimationObserver can handle deleted window.
TEST_P(OverviewSessionTest,OverviewWindowAnimationObserverCanHandleDeletedWindow)2013 TEST_P(OverviewSessionTest,
2014 OverviewWindowAnimationObserverCanHandleDeletedWindow) {
2015 std::unique_ptr<aura::Window> window1(CreateTestWindow());
2016 std::unique_ptr<aura::Window> window2(CreateTestWindow());
2017 std::unique_ptr<aura::Window> window3(CreateTestWindow());
2018 wm::ActivateWindow(window3.get());
2019 wm::ActivateWindow(window2.get());
2020 wm::ActivateWindow(window1.get());
2021
2022 EXPECT_FALSE(WindowState::Get(window1.get())->IsFullscreen());
2023 EXPECT_FALSE(WindowState::Get(window2.get())->IsFullscreen());
2024 EXPECT_FALSE(WindowState::Get(window3.get())->IsFullscreen());
2025
2026 const WMEvent toggle_fullscreen_event(WM_EVENT_TOGGLE_FULLSCREEN);
2027 WindowState::Get(window2.get())->OnWMEvent(&toggle_fullscreen_event);
2028 WindowState::Get(window3.get())->OnWMEvent(&toggle_fullscreen_event);
2029 EXPECT_FALSE(WindowState::Get(window1.get())->IsFullscreen());
2030 EXPECT_TRUE(WindowState::Get(window2.get())->IsFullscreen());
2031 EXPECT_TRUE(WindowState::Get(window3.get())->IsFullscreen());
2032
2033 // Enter overview.
2034 ToggleOverview();
2035
2036 ui::ScopedAnimationDurationScaleMode test_duration_mode(
2037 ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
2038 // Click on |window3| to activate it and exit overview.
2039 // Should only set |should_animate_when_exiting_| and
2040 // |should_be_observed_when_exiting_| on window 3.
2041 {
2042 TweenTester tester1(window1.get());
2043 TweenTester tester2(window2.get());
2044 TweenTester tester3(window3.get());
2045 ClickWindow(window3.get());
2046 EXPECT_EQ(gfx::Tween::ZERO, tester1.tween_type());
2047 EXPECT_EQ(gfx::Tween::ZERO, tester2.tween_type());
2048 EXPECT_EQ(gfx::Tween::EASE_OUT, tester3.tween_type());
2049 }
2050 // Destroy |window1| and |window2| before |window3| finishes animation can be
2051 // handled in OverviewWindowAnimationObserver.
2052 window1.reset();
2053 window2.reset();
2054 }
2055
2056 // Tests can handle OverviewWindowAnimationObserver was deleted.
TEST_P(OverviewSessionTest,HandleOverviewWindowAnimationObserverWasDeleted)2057 TEST_P(OverviewSessionTest, HandleOverviewWindowAnimationObserverWasDeleted) {
2058 std::unique_ptr<aura::Window> window1(CreateTestWindow());
2059 std::unique_ptr<aura::Window> window2(CreateTestWindow());
2060 std::unique_ptr<aura::Window> window3(CreateTestWindow());
2061 wm::ActivateWindow(window3.get());
2062 wm::ActivateWindow(window2.get());
2063 wm::ActivateWindow(window1.get());
2064
2065 EXPECT_FALSE(WindowState::Get(window1.get())->IsFullscreen());
2066 EXPECT_FALSE(WindowState::Get(window2.get())->IsFullscreen());
2067 EXPECT_FALSE(WindowState::Get(window3.get())->IsFullscreen());
2068
2069 const WMEvent toggle_fullscreen_event(WM_EVENT_TOGGLE_FULLSCREEN);
2070 WindowState::Get(window2.get())->OnWMEvent(&toggle_fullscreen_event);
2071 WindowState::Get(window3.get())->OnWMEvent(&toggle_fullscreen_event);
2072 EXPECT_FALSE(WindowState::Get(window1.get())->IsFullscreen());
2073 EXPECT_TRUE(WindowState::Get(window2.get())->IsFullscreen());
2074 EXPECT_TRUE(WindowState::Get(window3.get())->IsFullscreen());
2075
2076 // Enter overview.
2077 ToggleOverview();
2078
2079 // Click on |window2| to activate it and exit overview. Should only set
2080 // |should_animate_when_exiting_| and |should_be_observed_when_exiting_| on
2081 // window 2. Because the animation duration is zero in test, the
2082 // OverviewWindowAnimationObserver will delete itself immediately before
2083 // |window3| is added to it.
2084 ClickWindow(window2.get());
2085 EXPECT_FALSE(window1->layer()->GetAnimator()->is_animating());
2086 EXPECT_FALSE(window2->layer()->GetAnimator()->is_animating());
2087 EXPECT_FALSE(window3->layer()->GetAnimator()->is_animating());
2088 }
2089
2090 // Tests can handle |gained_active| window is not in the |overview_grid| when
2091 // OnWindowActivated.
TEST_P(OverviewSessionTest,HandleActiveWindowNotInOverviewGrid)2092 TEST_P(OverviewSessionTest, HandleActiveWindowNotInOverviewGrid) {
2093 std::unique_ptr<aura::Window> window1(CreateTestWindow());
2094 std::unique_ptr<aura::Window> window2(CreateTestWindow());
2095 std::unique_ptr<aura::Window> window3(CreateTestWindow());
2096 wm::ActivateWindow(window3.get());
2097 wm::ActivateWindow(window2.get());
2098 wm::ActivateWindow(window1.get());
2099
2100 EXPECT_FALSE(WindowState::Get(window1.get())->IsFullscreen());
2101 EXPECT_FALSE(WindowState::Get(window2.get())->IsFullscreen());
2102 EXPECT_FALSE(WindowState::Get(window3.get())->IsFullscreen());
2103
2104 const WMEvent toggle_fullscreen_event(WM_EVENT_TOGGLE_FULLSCREEN);
2105 WindowState::Get(window2.get())->OnWMEvent(&toggle_fullscreen_event);
2106 WindowState::Get(window3.get())->OnWMEvent(&toggle_fullscreen_event);
2107 EXPECT_FALSE(WindowState::Get(window1.get())->IsFullscreen());
2108 EXPECT_TRUE(WindowState::Get(window2.get())->IsFullscreen());
2109 EXPECT_TRUE(WindowState::Get(window3.get())->IsFullscreen());
2110
2111 // Enter overview.
2112 ToggleOverview();
2113
2114 ui::ScopedAnimationDurationScaleMode test_duration_mode(
2115 ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
2116 // Create and active a new window should exit overview without error.
2117 auto widget = CreateTestWidget();
2118
2119 TweenTester tester1(window1.get());
2120 TweenTester tester2(window2.get());
2121 TweenTester tester3(window3.get());
2122
2123 ClickWindow(widget->GetNativeWindow());
2124
2125 // |window1| and |window2| should animate.
2126 EXPECT_EQ(gfx::Tween::EASE_OUT, tester1.tween_type());
2127 EXPECT_EQ(gfx::Tween::EASE_OUT, tester2.tween_type());
2128 EXPECT_EQ(gfx::Tween::ZERO, tester3.tween_type());
2129 }
2130
2131 // Tests that AlwaysOnTopWindow can be handled correctly in new overview
2132 // animations.
2133 // Fails consistently; see https://crbug.com/812497.
TEST_P(OverviewSessionTest,DISABLED_HandleAlwaysOnTopWindow)2134 TEST_P(OverviewSessionTest, DISABLED_HandleAlwaysOnTopWindow) {
2135 const gfx::Rect bounds(400, 400);
2136 std::unique_ptr<aura::Window> window1(CreateTestWindow(bounds));
2137 std::unique_ptr<aura::Window> window2(CreateTestWindow(bounds));
2138 std::unique_ptr<aura::Window> window3(CreateTestWindow(bounds));
2139 std::unique_ptr<aura::Window> window4(CreateTestWindow(bounds));
2140 std::unique_ptr<aura::Window> window5(CreateTestWindow(bounds));
2141 std::unique_ptr<aura::Window> window6(CreateTestWindow(bounds));
2142 std::unique_ptr<aura::Window> window7(CreateTestWindow(bounds));
2143 std::unique_ptr<aura::Window> window8(CreateTestWindow(bounds));
2144 window3->SetProperty(aura::client::kZOrderingKey,
2145 ui::ZOrderLevel::kFloatingWindow);
2146 window5->SetProperty(aura::client::kZOrderingKey,
2147 ui::ZOrderLevel::kFloatingWindow);
2148
2149 // Control z order and MRU order.
2150 wm::ActivateWindow(window8.get());
2151 wm::ActivateWindow(window7.get()); // Will be fullscreen.
2152 wm::ActivateWindow(window6.get()); // Will be maximized.
2153 wm::ActivateWindow(window5.get()); // AlwaysOnTop window.
2154 wm::ActivateWindow(window4.get());
2155 wm::ActivateWindow(window3.get()); // AlwaysOnTop window.
2156 wm::ActivateWindow(window2.get()); // Will be fullscreen.
2157 wm::ActivateWindow(window1.get());
2158
2159 EXPECT_FALSE(WindowState::Get(window2.get())->IsFullscreen());
2160 EXPECT_FALSE(WindowState::Get(window6.get())->IsFullscreen());
2161 EXPECT_FALSE(WindowState::Get(window7.get())->IsMaximized());
2162
2163 const WMEvent toggle_maximize_event(WM_EVENT_TOGGLE_MAXIMIZE);
2164 WindowState::Get(window6.get())->OnWMEvent(&toggle_maximize_event);
2165 const WMEvent toggle_fullscreen_event(WM_EVENT_TOGGLE_FULLSCREEN);
2166 WindowState::Get(window2.get())->OnWMEvent(&toggle_fullscreen_event);
2167 WindowState::Get(window7.get())->OnWMEvent(&toggle_fullscreen_event);
2168 EXPECT_TRUE(WindowState::Get(window2.get())->IsFullscreen());
2169 EXPECT_TRUE(WindowState::Get(window7.get())->IsFullscreen());
2170 EXPECT_TRUE(WindowState::Get(window6.get())->IsMaximized());
2171
2172 // Case 1: Click on |window1| to activate it and exit overview.
2173 std::unique_ptr<ui::ScopedAnimationDurationScaleMode> test_duration_mode =
2174 std::make_unique<ui::ScopedAnimationDurationScaleMode>(
2175 ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
2176 ToggleOverview();
2177 // For entering animation, only animate |window1|, |window2|, |window3| and
2178 // |window5| because |window3| and |window5| are AlwaysOnTop windows and
2179 // |window2| is fullscreen.
2180 EXPECT_TRUE(window1->layer()->GetAnimator()->is_animating());
2181 EXPECT_TRUE(window2->layer()->GetAnimator()->is_animating());
2182 EXPECT_TRUE(window3->layer()->GetAnimator()->is_animating());
2183 EXPECT_FALSE(window4->layer()->GetAnimator()->is_animating());
2184 EXPECT_TRUE(window5->layer()->GetAnimator()->is_animating());
2185 EXPECT_FALSE(window6->layer()->GetAnimator()->is_animating());
2186 EXPECT_FALSE(window7->layer()->GetAnimator()->is_animating());
2187 EXPECT_FALSE(window8->layer()->GetAnimator()->is_animating());
2188 base::RunLoop().RunUntilIdle();
2189
2190 // Click on |window1| to activate it and exit overview.
2191 // Should animate |window1|, |window2|, |window3| and |window5| because
2192 // |window3| and |window5| are AlwaysOnTop windows and |window2| is
2193 // fullscreen.
2194 ClickWindow(window1.get());
2195 EXPECT_TRUE(window1->layer()->GetAnimator()->is_animating());
2196 EXPECT_TRUE(window2->layer()->GetAnimator()->is_animating());
2197 EXPECT_TRUE(window3->layer()->GetAnimator()->is_animating());
2198 EXPECT_FALSE(window4->layer()->GetAnimator()->is_animating());
2199 EXPECT_TRUE(window5->layer()->GetAnimator()->is_animating());
2200 EXPECT_FALSE(window6->layer()->GetAnimator()->is_animating());
2201 EXPECT_FALSE(window7->layer()->GetAnimator()->is_animating());
2202 EXPECT_FALSE(window8->layer()->GetAnimator()->is_animating());
2203 base::RunLoop().RunUntilIdle();
2204
2205 // Case 2: Click on |window3| to activate it and exit overview.
2206 // Should animate |window1|, |window2|, |window3| and |window5|.
2207 // Reset window z-order. Need to toggle fullscreen first to workaround
2208 // https://crbug.com/816224.
2209 WindowState::Get(window2.get())->OnWMEvent(&toggle_fullscreen_event);
2210 WindowState::Get(window7.get())->OnWMEvent(&toggle_fullscreen_event);
2211 wm::ActivateWindow(window8.get());
2212 wm::ActivateWindow(window7.get()); // Will be fullscreen.
2213 wm::ActivateWindow(window6.get()); // Maximized.
2214 wm::ActivateWindow(window5.get()); // AlwaysOnTop window.
2215 wm::ActivateWindow(window4.get());
2216 wm::ActivateWindow(window3.get()); // AlwaysOnTop window.
2217 wm::ActivateWindow(window2.get()); // Will be fullscreen.
2218 wm::ActivateWindow(window1.get());
2219 WindowState::Get(window2.get())->OnWMEvent(&toggle_fullscreen_event);
2220 WindowState::Get(window7.get())->OnWMEvent(&toggle_fullscreen_event);
2221 // Enter overview.
2222 test_duration_mode = std::make_unique<ui::ScopedAnimationDurationScaleMode>(
2223 ui::ScopedAnimationDurationScaleMode::ZERO_DURATION);
2224 ToggleOverview();
2225 base::RunLoop().RunUntilIdle();
2226 test_duration_mode = std::make_unique<ui::ScopedAnimationDurationScaleMode>(
2227 ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
2228
2229 ClickWindow(window3.get());
2230 EXPECT_TRUE(window1->layer()->GetAnimator()->is_animating());
2231 EXPECT_TRUE(window2->layer()->GetAnimator()->is_animating());
2232 EXPECT_TRUE(window3->layer()->GetAnimator()->is_animating());
2233 EXPECT_FALSE(window4->layer()->GetAnimator()->is_animating());
2234 EXPECT_TRUE(window5->layer()->GetAnimator()->is_animating());
2235 EXPECT_FALSE(window6->layer()->GetAnimator()->is_animating());
2236 EXPECT_FALSE(window7->layer()->GetAnimator()->is_animating());
2237 EXPECT_FALSE(window8->layer()->GetAnimator()->is_animating());
2238 base::RunLoop().RunUntilIdle();
2239
2240 // Case 3: Click on maximized |window6| to activate it and exit overview.
2241 // Should animate |window6|, |window3| and |window5| because |window3| and
2242 // |window5| are AlwaysOnTop windows. |window6| is maximized.
2243 // Reset window z-order. Need to toggle fullscreen first to workaround
2244 // https://crbug.com/816224.
2245 WindowState::Get(window2.get())->OnWMEvent(&toggle_fullscreen_event);
2246 WindowState::Get(window7.get())->OnWMEvent(&toggle_fullscreen_event);
2247 wm::ActivateWindow(window8.get());
2248 wm::ActivateWindow(window7.get()); // Will be fullscreen.
2249 wm::ActivateWindow(window6.get()); // Maximized.
2250 wm::ActivateWindow(window5.get()); // AlwaysOnTop window.
2251 wm::ActivateWindow(window4.get());
2252 wm::ActivateWindow(window3.get()); // AlwaysOnTop window.
2253 wm::ActivateWindow(window2.get()); // Will be fullscreen.
2254 wm::ActivateWindow(window1.get());
2255 WindowState::Get(window2.get())->OnWMEvent(&toggle_fullscreen_event);
2256 WindowState::Get(window7.get())->OnWMEvent(&toggle_fullscreen_event);
2257 // Enter overview.
2258 test_duration_mode = std::make_unique<ui::ScopedAnimationDurationScaleMode>(
2259 ui::ScopedAnimationDurationScaleMode::ZERO_DURATION);
2260 ToggleOverview();
2261 base::RunLoop().RunUntilIdle();
2262 test_duration_mode = std::make_unique<ui::ScopedAnimationDurationScaleMode>(
2263 ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
2264
2265 ClickWindow(window6.get());
2266 EXPECT_FALSE(window1->layer()->GetAnimator()->is_animating());
2267 EXPECT_FALSE(window2->layer()->GetAnimator()->is_animating());
2268 EXPECT_TRUE(window3->layer()->GetAnimator()->is_animating());
2269 EXPECT_FALSE(window4->layer()->GetAnimator()->is_animating());
2270 EXPECT_TRUE(window5->layer()->GetAnimator()->is_animating());
2271 EXPECT_TRUE(window6->layer()->GetAnimator()->is_animating());
2272 EXPECT_FALSE(window7->layer()->GetAnimator()->is_animating());
2273 EXPECT_FALSE(window8->layer()->GetAnimator()->is_animating());
2274 base::RunLoop().RunUntilIdle();
2275
2276 // Case 4: Click on |window8| to activate it and exit overview.
2277 // Should animate |window8|, |window1|, |window2|, |window3| and |window5|
2278 // because |window3| and |window5| are AlwaysOnTop windows and |window2| is
2279 // fullscreen.
2280 // Reset window z-order. Need to toggle fullscreen first to workaround
2281 // https://crbug.com/816224.
2282 WindowState::Get(window2.get())->OnWMEvent(&toggle_fullscreen_event);
2283 WindowState::Get(window7.get())->OnWMEvent(&toggle_fullscreen_event);
2284 wm::ActivateWindow(window8.get());
2285 wm::ActivateWindow(window7.get()); // Will be fullscreen.
2286 wm::ActivateWindow(window6.get()); // Maximized.
2287 wm::ActivateWindow(window5.get()); // AlwaysOnTop window.
2288 wm::ActivateWindow(window4.get());
2289 wm::ActivateWindow(window3.get()); // AlwaysOnTop window.
2290 wm::ActivateWindow(window2.get()); // Will be fullscreen.
2291 wm::ActivateWindow(window1.get());
2292 WindowState::Get(window2.get())->OnWMEvent(&toggle_fullscreen_event);
2293 WindowState::Get(window7.get())->OnWMEvent(&toggle_fullscreen_event);
2294 // Enter overview.
2295 test_duration_mode = std::make_unique<ui::ScopedAnimationDurationScaleMode>(
2296 ui::ScopedAnimationDurationScaleMode::ZERO_DURATION);
2297 ToggleOverview();
2298 base::RunLoop().RunUntilIdle();
2299 test_duration_mode = std::make_unique<ui::ScopedAnimationDurationScaleMode>(
2300 ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
2301
2302 ClickWindow(window8.get());
2303 EXPECT_TRUE(window1->layer()->GetAnimator()->is_animating());
2304 EXPECT_TRUE(window2->layer()->GetAnimator()->is_animating());
2305 EXPECT_TRUE(window3->layer()->GetAnimator()->is_animating());
2306 EXPECT_FALSE(window4->layer()->GetAnimator()->is_animating());
2307 EXPECT_TRUE(window5->layer()->GetAnimator()->is_animating());
2308 EXPECT_FALSE(window6->layer()->GetAnimator()->is_animating());
2309 EXPECT_FALSE(window7->layer()->GetAnimator()->is_animating());
2310 EXPECT_TRUE(window8->layer()->GetAnimator()->is_animating());
2311 base::RunLoop().RunUntilIdle();
2312 }
2313
2314 // Verify that the selector item can animate after the item is dragged and
2315 // released.
TEST_P(OverviewSessionTest,WindowItemCanAnimateOnDragRelease)2316 TEST_P(OverviewSessionTest, WindowItemCanAnimateOnDragRelease) {
2317 base::HistogramTester histogram_tester;
2318 UpdateDisplay("400x400");
2319 std::unique_ptr<aura::Window> window1(CreateTestWindow());
2320 std::unique_ptr<aura::Window> window2(CreateTestWindow());
2321 wm::ActivateWindow(window2.get());
2322 wm::ActivateWindow(window1.get());
2323
2324 EnterTabletMode();
2325 ToggleOverview();
2326 OverviewItem* item2 = GetOverviewItemForWindow(window2.get());
2327 // Drag |item2| in a way so that |window2| does not get activated.
2328 ui::test::EventGenerator* generator = GetEventGenerator();
2329 generator->MoveMouseTo(
2330 gfx::ToRoundedPoint(item2->target_bounds().CenterPoint()));
2331 generator->PressLeftButton();
2332 base::RunLoop().RunUntilIdle();
2333
2334 generator->MoveMouseTo(gfx::Point(200, 200));
2335 histogram_tester.ExpectTotalCount(
2336 "Ash.Overview.WindowDrag.PresentationTime.TabletMode", 1);
2337 histogram_tester.ExpectTotalCount(
2338 "Ash.Overview.WindowDrag.PresentationTime.MaxLatency.TabletMode", 0);
2339
2340 ui::ScopedAnimationDurationScaleMode test_duration_mode(
2341 ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
2342 generator->ReleaseLeftButton();
2343 EXPECT_TRUE(window2->layer()->GetAnimator()->IsAnimatingProperty(
2344 ui::LayerAnimationElement::AnimatableProperty::TRANSFORM));
2345 base::RunLoop().RunUntilIdle();
2346 histogram_tester.ExpectTotalCount(
2347 "Ash.Overview.WindowDrag.PresentationTime.TabletMode", 1);
2348 histogram_tester.ExpectTotalCount(
2349 "Ash.Overview.WindowDrag.PresentationTime.MaxLatency.TabletMode", 1);
2350 }
2351
2352 // Verify that the overview items titlebar and close button change visibility
2353 // when a item is being dragged.
TEST_P(OverviewSessionTest,OverviewItemTitleCloseVisibilityOnDrag)2354 TEST_P(OverviewSessionTest, OverviewItemTitleCloseVisibilityOnDrag) {
2355 base::HistogramTester histogram_tester;
2356 UpdateDisplay("400x400");
2357 std::unique_ptr<aura::Window> window1(CreateTestWindow());
2358 std::unique_ptr<aura::Window> window2(CreateTestWindow());
2359
2360 EnterTabletMode();
2361 ToggleOverview();
2362 OverviewItem* item1 = GetOverviewItemForWindow(window1.get());
2363 OverviewItem* item2 = GetOverviewItemForWindow(window2.get());
2364 // Start the drag on |item1|. Verify the dragged item, |item1| has both the
2365 // close button and titlebar hidden. The close button opacity however is
2366 // opaque as its a child of the header which handles fading away the whole
2367 // header. All other items, |item2| should only have the close button hidden.
2368 ui::test::EventGenerator* generator = GetEventGenerator();
2369 generator->MoveMouseTo(
2370 gfx::ToRoundedPoint(item1->target_bounds().CenterPoint()));
2371 generator->PressLeftButton();
2372 base::RunLoop().RunUntilIdle();
2373 EXPECT_EQ(0.f, GetTitlebarOpacity(item1));
2374 EXPECT_EQ(1.f, GetCloseButtonOpacity(item1));
2375 EXPECT_EQ(1.f, GetTitlebarOpacity(item2));
2376 EXPECT_EQ(0.f, GetCloseButtonOpacity(item2));
2377
2378 // Drag |item1| in a way so that |window1| does not get activated (drags
2379 // within a certain threshold count as clicks). Verify the close button and
2380 // titlebar is visible for all items.
2381 generator->MoveMouseTo(gfx::Point(200, 200));
2382 histogram_tester.ExpectTotalCount(
2383 "Ash.Overview.WindowDrag.PresentationTime.TabletMode", 1);
2384 histogram_tester.ExpectTotalCount(
2385 "Ash.Overview.WindowDrag.PresentationTime.MaxLatency.TabletMode", 0);
2386
2387 generator->ReleaseLeftButton();
2388 base::RunLoop().RunUntilIdle();
2389 EXPECT_EQ(1.f, GetTitlebarOpacity(item1));
2390 EXPECT_EQ(1.f, GetCloseButtonOpacity(item1));
2391 EXPECT_EQ(1.f, GetTitlebarOpacity(item2));
2392 EXPECT_EQ(1.f, GetCloseButtonOpacity(item2));
2393 histogram_tester.ExpectTotalCount(
2394 "Ash.Overview.WindowDrag.PresentationTime.TabletMode", 1);
2395 histogram_tester.ExpectTotalCount(
2396 "Ash.Overview.WindowDrag.PresentationTime.MaxLatency.TabletMode", 1);
2397 }
2398
2399 // Tests that overview widgets are stacked in the correct order.
TEST_P(OverviewSessionTest,OverviewWidgetStackingOrder)2400 TEST_P(OverviewSessionTest, OverviewWidgetStackingOrder) {
2401 base::HistogramTester histogram_tester;
2402 // Create three windows, including one minimized.
2403 std::unique_ptr<aura::Window> minimized(CreateTestWindow());
2404 WindowState::Get(minimized.get())->Minimize();
2405 std::unique_ptr<aura::Window> window(CreateTestWindow());
2406 std::unique_ptr<aura::Window> window3(CreateTestWindow());
2407
2408 aura::Window* parent = window->parent();
2409 EXPECT_EQ(parent, minimized->parent());
2410
2411 EnterTabletMode();
2412 ToggleOverview();
2413 OverviewItem* item1 = GetOverviewItemForWindow(minimized.get());
2414 OverviewItem* item2 = GetOverviewItemForWindow(window.get());
2415 OverviewItem* item3 = GetOverviewItemForWindow(window3.get());
2416
2417 views::Widget* widget1 = item1->item_widget();
2418 views::Widget* widget2 = item2->item_widget();
2419 views::Widget* widget3 = item3->item_widget();
2420
2421 // The original order of stacking is determined by the order the associated
2422 // window was activated.
2423 EXPECT_GT(IndexOf(widget3->GetNativeWindow(), parent),
2424 IndexOf(widget2->GetNativeWindow(), parent));
2425 EXPECT_GT(IndexOf(widget2->GetNativeWindow(), parent),
2426 IndexOf(widget1->GetNativeWindow(), parent));
2427
2428 // Verify that the item widget is stacked below the window.
2429 EXPECT_LT(IndexOf(widget1->GetNativeWindow(), parent),
2430 IndexOf(minimized.get(), parent));
2431 EXPECT_LT(IndexOf(widget2->GetNativeWindow(), parent),
2432 IndexOf(window.get(), parent));
2433 EXPECT_LT(IndexOf(widget3->GetNativeWindow(), parent),
2434 IndexOf(window3.get(), parent));
2435
2436 // Drag the first window. Verify that it's item widget is not stacked above
2437 // the other two.
2438 const gfx::Point start_drag =
2439 gfx::ToRoundedPoint(item1->target_bounds().CenterPoint());
2440 ui::test::EventGenerator* generator = GetEventGenerator();
2441 generator->MoveMouseTo(start_drag);
2442 generator->PressLeftButton();
2443 EXPECT_GT(IndexOf(widget1->GetNativeWindow(), parent),
2444 IndexOf(widget2->GetNativeWindow(), parent));
2445 EXPECT_GT(IndexOf(widget1->GetNativeWindow(), parent),
2446 IndexOf(widget3->GetNativeWindow(), parent));
2447 histogram_tester.ExpectTotalCount(
2448 "Ash.Overview.WindowDrag.PresentationTime.TabletMode", 0);
2449
2450 // Drag to origin and then back to the start to avoid activating the window or
2451 // entering splitview.
2452 generator->MoveMouseTo(gfx::Point());
2453 histogram_tester.ExpectTotalCount(
2454 "Ash.Overview.WindowDrag.PresentationTime.TabletMode", 1);
2455
2456 generator->MoveMouseTo(start_drag);
2457 histogram_tester.ExpectTotalCount(
2458 "Ash.Overview.WindowDrag.PresentationTime.TabletMode", 2);
2459 histogram_tester.ExpectTotalCount(
2460 "Ash.Overview.WindowDrag.PresentationTime.MaxLatency.TabletMode", 0);
2461
2462 generator->ReleaseLeftButton();
2463
2464 // Verify the stacking order is same as before dragging started.
2465 EXPECT_GT(IndexOf(widget3->GetNativeWindow(), parent),
2466 IndexOf(widget2->GetNativeWindow(), parent));
2467 EXPECT_GT(IndexOf(widget2->GetNativeWindow(), parent),
2468 IndexOf(widget1->GetNativeWindow(), parent));
2469
2470 histogram_tester.ExpectTotalCount(
2471 "Ash.Overview.WindowDrag.PresentationTime.TabletMode", 2);
2472 histogram_tester.ExpectTotalCount(
2473 "Ash.Overview.WindowDrag.PresentationTime.MaxLatency.TabletMode", 1);
2474 }
2475
2476 // Test that dragging a window from the top creates a drop target stacked at the
2477 // bottom. Test that dropping into overview removes the drop target.
TEST_P(OverviewSessionTest,DropTargetStackedAtBottomForWindowDraggedFromTop)2478 TEST_P(OverviewSessionTest, DropTargetStackedAtBottomForWindowDraggedFromTop) {
2479 UpdateDisplay("800x600");
2480 EnterTabletMode();
2481 std::unique_ptr<aura::Window> window1(CreateTestWindow());
2482 window1->SetProperty(aura::client::kAppType,
2483 static_cast<int>(AppType::BROWSER));
2484 std::unique_ptr<aura::Window> window2(CreateTestWindow());
2485 aura::Window* parent = window1->parent();
2486 ASSERT_EQ(parent, window2->parent());
2487 wm::ActivateWindow(window2.get());
2488 wm::ActivateWindow(window1.get());
2489 std::unique_ptr<WindowResizer> resizer =
2490 CreateWindowResizer(window1.get(), gfx::PointF(400, 0), HTCAPTION,
2491 ::wm::WINDOW_MOVE_SOURCE_TOUCH);
2492 ASSERT_TRUE(GetDropTarget(0));
2493 EXPECT_LT(IndexOf(GetDropTarget(0)->GetWindow(), parent),
2494 IndexOf(window2.get(), parent));
2495 resizer->Drag(gfx::PointF(400, 500), ui::EF_NONE);
2496 resizer->CompleteDrag();
2497 EXPECT_FALSE(GetDropTarget(0));
2498 }
2499
2500 // Test that dragging an overview item to snap creates a drop target stacked at
2501 // the bottom. Test that ending the drag removes the drop target.
TEST_P(OverviewSessionTest,DropTargetStackedAtBottomForOverviewItem)2502 TEST_P(OverviewSessionTest, DropTargetStackedAtBottomForOverviewItem) {
2503 EnterTabletMode();
2504 std::unique_ptr<aura::Window> window1(CreateTestWindow());
2505 std::unique_ptr<aura::Window> window2(CreateTestWindow());
2506 aura::Window* parent = window1->parent();
2507 ASSERT_EQ(parent, window2->parent());
2508 wm::ActivateWindow(window2.get());
2509 wm::ActivateWindow(window1.get());
2510 ToggleOverview();
2511 ui::test::EventGenerator* generator = GetEventGenerator();
2512 generator->MoveMouseTo(gfx::ToRoundedPoint(
2513 GetOverviewItemForWindow(window1.get())->target_bounds().CenterPoint()));
2514 generator->PressLeftButton();
2515 generator->MoveMouseBy(5, 0);
2516 ASSERT_TRUE(GetDropTarget(0));
2517 EXPECT_LT(IndexOf(GetDropTarget(0)->GetWindow(), parent),
2518 IndexOf(window2.get(), parent));
2519 generator->ReleaseLeftButton();
2520 EXPECT_FALSE(GetDropTarget(0));
2521 }
2522
2523 // Verify that a windows which enter overview mode have a visible backdrop, if
2524 // the window is to be letter or pillar fitted.
TEST_P(OverviewSessionTest,Backdrop)2525 TEST_P(OverviewSessionTest, Backdrop) {
2526 // Add three windows which in overview mode will be considered wide, tall and
2527 // normal. Window |wide|, with size (400, 160) will be resized to (300, 160)
2528 // when the 400x300 is rotated to 300x400, and should be considered a normal
2529 // overview window after display change.
2530 UpdateDisplay("400x300");
2531 std::unique_ptr<aura::Window> wide(CreateTestWindow(gfx::Rect(400, 160)));
2532 std::unique_ptr<aura::Window> tall(CreateTestWindow(gfx::Rect(100, 300)));
2533 std::unique_ptr<aura::Window> normal(CreateTestWindow(gfx::Rect(300, 300)));
2534
2535 ToggleOverview();
2536 base::RunLoop().RunUntilIdle();
2537 OverviewItem* wide_item = GetOverviewItemForWindow(wide.get());
2538 OverviewItem* tall_item = GetOverviewItemForWindow(tall.get());
2539 OverviewItem* normal_item = GetOverviewItemForWindow(normal.get());
2540
2541 // Only very tall and very wide windows will have a backdrop. The backdrop
2542 // only gets created if we need it once during the overview session.
2543 ASSERT_TRUE(GetBackdropView(wide_item));
2544 EXPECT_TRUE(GetBackdropView(wide_item)->GetVisible());
2545 EXPECT_TRUE(GetBackdropView(tall_item));
2546 ASSERT_TRUE(GetBackdropView(tall_item)->GetVisible());
2547 EXPECT_FALSE(GetBackdropView(normal_item));
2548
2549 display::Screen* screen = display::Screen::GetScreen();
2550 const display::Display& display = screen->GetPrimaryDisplay();
2551 display_manager()->SetDisplayRotation(
2552 display.id(), display::Display::ROTATE_90,
2553 display::Display::RotationSource::ACTIVE);
2554
2555 // After rotation the former wide window will be a normal window and its
2556 // backdrop will still be there but invisible.
2557 ASSERT_TRUE(GetBackdropView(wide_item));
2558 EXPECT_FALSE(GetBackdropView(wide_item)->GetVisible());
2559 EXPECT_TRUE(GetBackdropView(tall_item));
2560 ASSERT_TRUE(GetBackdropView(tall_item)->GetVisible());
2561 EXPECT_FALSE(GetBackdropView(normal_item));
2562
2563 // Test that leaving overview mode cleans up properly.
2564 ToggleOverview();
2565 }
2566
2567 // Test that the rounded corners are removed during animations.
TEST_P(OverviewSessionTest,RoundedCornersVisibility)2568 TEST_P(OverviewSessionTest, RoundedCornersVisibility) {
2569 std::unique_ptr<aura::Window> window1(CreateTestWindow());
2570 std::unique_ptr<aura::Window> window2(CreateTestWindow());
2571
2572 wm::ActivateWindow(window2.get());
2573 wm::ActivateWindow(window1.get());
2574
2575 ui::ScopedAnimationDurationScaleMode test_duration_mode(
2576 ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
2577
2578 // Test that entering overview mode normally will disable all the rounded
2579 // corners until the animation is complete.
2580 EnterTabletMode();
2581 ToggleOverview();
2582 OverviewItem* item1 = GetOverviewItemForWindow(window1.get());
2583 OverviewItem* item2 = GetOverviewItemForWindow(window2.get());
2584 EXPECT_FALSE(HasRoundedCorner(item1));
2585 EXPECT_FALSE(HasRoundedCorner(item2));
2586 ShellTestApi().WaitForOverviewAnimationState(
2587 OverviewAnimationState::kEnterAnimationComplete);
2588 EXPECT_TRUE(HasRoundedCorner(item1));
2589 EXPECT_TRUE(HasRoundedCorner(item2));
2590
2591 // Tests that entering overview mode with all windows minimized (launcher
2592 // button pressed) will still disable all the rounded corners until the
2593 // animation is complete.
2594 ToggleOverview();
2595 ShellTestApi().WaitForOverviewAnimationState(
2596 OverviewAnimationState::kExitAnimationComplete);
2597 WindowState::Get(window1.get())->Minimize();
2598 WindowState::Get(window2.get())->Minimize();
2599
2600 ToggleOverview();
2601 item1 = GetOverviewItemForWindow(window1.get());
2602 item2 = GetOverviewItemForWindow(window2.get());
2603 EXPECT_FALSE(HasRoundedCorner(item1));
2604 EXPECT_FALSE(HasRoundedCorner(item2));
2605 ShellTestApi().WaitForOverviewAnimationState(
2606 OverviewAnimationState::kEnterAnimationComplete);
2607 EXPECT_TRUE(HasRoundedCorner(item1));
2608 EXPECT_TRUE(HasRoundedCorner(item2));
2609
2610 // Test that leaving overview mode cleans up properly.
2611 ToggleOverview();
2612 ShellTestApi().WaitForOverviewAnimationState(
2613 OverviewAnimationState::kExitAnimationComplete);
2614 }
2615
2616 // Test that the shadow disappears while dragging an overview item.
TEST_P(OverviewSessionTest,ShadowVisibilityDragging)2617 TEST_P(OverviewSessionTest, ShadowVisibilityDragging) {
2618 std::unique_ptr<aura::Window> window1(CreateTestWindow());
2619 std::unique_ptr<aura::Window> window2(CreateTestWindow());
2620
2621 wm::ActivateWindow(window2.get());
2622 wm::ActivateWindow(window1.get());
2623
2624 EnterTabletMode();
2625 ToggleOverview();
2626 OverviewItem* item1 = GetOverviewItemForWindow(window1.get());
2627 OverviewItem* item2 = GetOverviewItemForWindow(window2.get());
2628 ui::ScopedAnimationDurationScaleMode test_duration_mode(
2629 ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
2630
2631 // Drag the first window. Verify that the shadow was removed for the first
2632 // window but still exists for the second window as we do not make shadow
2633 // for a dragged window.
2634 const gfx::Point start_drag =
2635 gfx::ToRoundedPoint(item1->target_bounds().CenterPoint());
2636 ui::test::EventGenerator* generator = GetEventGenerator();
2637 generator->MoveMouseTo(start_drag);
2638 generator->PressLeftButton();
2639 EXPECT_FALSE(window1->layer()->GetAnimator()->is_animating());
2640 EXPECT_FALSE(window2->layer()->GetAnimator()->is_animating());
2641
2642 EXPECT_TRUE(item1->GetShadowBoundsForTesting().IsEmpty());
2643 EXPECT_FALSE(item2->GetShadowBoundsForTesting().IsEmpty());
2644
2645 // Drag to horizontally and then back to the start to avoid activating the
2646 // window, drag to close or entering splitview. Verify that the shadow is
2647 // invisible on both items during animation.
2648 generator->MoveMouseTo(gfx::Point(0, start_drag.y()));
2649
2650 // The drop target window should be created with no shadow.
2651 OverviewItem* drop_target_item = GetDropTarget(0);
2652 ASSERT_TRUE(drop_target_item);
2653 EXPECT_TRUE(drop_target_item->GetShadowBoundsForTesting().IsEmpty());
2654
2655 generator->MoveMouseTo(start_drag);
2656 generator->ReleaseLeftButton();
2657 EXPECT_TRUE(window1->layer()->GetAnimator()->is_animating());
2658 EXPECT_TRUE(window2->layer()->GetAnimator()->is_animating());
2659 EXPECT_TRUE(item1->GetShadowBoundsForTesting().IsEmpty());
2660 EXPECT_TRUE(item2->GetShadowBoundsForTesting().IsEmpty());
2661
2662 // Verify that the shadow is visble again after animation is finished.
2663 window1->layer()->GetAnimator()->StopAnimating();
2664 window2->layer()->GetAnimator()->StopAnimating();
2665 EXPECT_FALSE(item1->GetShadowBoundsForTesting().IsEmpty());
2666 EXPECT_FALSE(item2->GetShadowBoundsForTesting().IsEmpty());
2667 }
2668
2669 // Tests that the shadows in overview mode are placed correctly.
TEST_P(OverviewSessionTest,ShadowBounds)2670 TEST_P(OverviewSessionTest, ShadowBounds) {
2671 // Helper function to check if the bounds of a shadow owned by |shadow_parent|
2672 // is contained within the bounds of |widget|.
2673 auto contains = [](views::Widget* widget, OverviewItem* shadow_parent) {
2674 return gfx::Rect(widget->GetNativeWindow()->bounds().size())
2675 .Contains(shadow_parent->GetShadowBoundsForTesting());
2676 };
2677
2678 // Helper function which returns the ratio of the shadow owned by
2679 // |shadow_parent| width and height.
2680 auto shadow_ratio = [](OverviewItem* shadow_parent) {
2681 gfx::RectF boundsf = gfx::RectF(shadow_parent->GetShadowBoundsForTesting());
2682 return boundsf.width() / boundsf.height();
2683 };
2684
2685 // Add three windows which in overview mode will be considered wide, tall and
2686 // normal. Set top view insets to 0 so it is easy to check the ratios of the
2687 // shadows match the ratios of the untransformed windows.
2688 UpdateDisplay("800x800");
2689 std::unique_ptr<aura::Window> wide(
2690 CreateTestWindowInShellWithDelegate(nullptr, -1, gfx::Rect(400, 100)));
2691 std::unique_ptr<aura::Window> tall(
2692 CreateTestWindowInShellWithDelegate(nullptr, -1, gfx::Rect(100, 400)));
2693 std::unique_ptr<aura::Window> normal(
2694 CreateTestWindowInShellWithDelegate(nullptr, -1, gfx::Rect(200, 200)));
2695 wide->SetProperty(aura::client::kTopViewInset, 0);
2696 tall->SetProperty(aura::client::kTopViewInset, 0);
2697 normal->SetProperty(aura::client::kTopViewInset, 0);
2698
2699 ToggleOverview();
2700 base::RunLoop().RunUntilIdle();
2701 OverviewItem* wide_item = GetOverviewItemForWindow(wide.get());
2702 OverviewItem* tall_item = GetOverviewItemForWindow(tall.get());
2703 OverviewItem* normal_item = GetOverviewItemForWindow(normal.get());
2704
2705 views::Widget* wide_widget = wide_item->item_widget();
2706 views::Widget* tall_widget = tall_item->item_widget();
2707 views::Widget* normal_widget = normal_item->item_widget();
2708
2709 OverviewGrid* grid = overview_session()->grid_list()[0].get();
2710
2711 // Verify all the shadows are within the bounds of their respective item
2712 // widgets when the overview windows are positioned without animations.
2713 SetGridBounds(grid, gfx::Rect(400, 800));
2714 grid->PositionWindows(false);
2715 EXPECT_TRUE(contains(wide_widget, wide_item));
2716 EXPECT_TRUE(contains(tall_widget, tall_item));
2717 EXPECT_TRUE(contains(normal_widget, normal_item));
2718
2719 // Verify the shadows preserve the ratios of the original windows.
2720 EXPECT_NEAR(shadow_ratio(wide_item), 4.f, 0.01f);
2721 EXPECT_NEAR(shadow_ratio(tall_item), 0.25f, 0.01f);
2722 EXPECT_NEAR(shadow_ratio(normal_item), 1.f, 0.01f);
2723
2724 // Verify all the shadows are within the bounds of their respective item
2725 // widgets when the overview windows are positioned with animations.
2726 SetGridBounds(grid, gfx::Rect(400, 800));
2727 grid->PositionWindows(true);
2728 base::RunLoop().RunUntilIdle();
2729 EXPECT_TRUE(contains(wide_widget, wide_item));
2730 EXPECT_TRUE(contains(tall_widget, tall_item));
2731 EXPECT_TRUE(contains(normal_widget, normal_item));
2732
2733 EXPECT_NEAR(shadow_ratio(wide_item), 4.f, 0.01f);
2734 EXPECT_NEAR(shadow_ratio(tall_item), 0.25f, 0.01f);
2735 EXPECT_NEAR(shadow_ratio(normal_item), 1.f, 0.01f);
2736
2737 // Test that leaving overview mode cleans up properly.
2738 ToggleOverview();
2739 }
2740
2741 // Verify that attempting to drag with a secondary finger works as expected.
TEST_P(OverviewSessionTest,DraggingWithTwoFingers)2742 TEST_P(OverviewSessionTest, DraggingWithTwoFingers) {
2743 std::unique_ptr<aura::Window> window1(CreateTestWindow());
2744 std::unique_ptr<aura::Window> window2(CreateTestWindow());
2745
2746 EnterTabletMode();
2747 ToggleOverview();
2748 OverviewItem* item1 = GetOverviewItemForWindow(window1.get());
2749 OverviewItem* item2 = GetOverviewItemForWindow(window2.get());
2750
2751 const gfx::RectF original_bounds1 = item1->target_bounds();
2752 const gfx::RectF original_bounds2 = item2->target_bounds();
2753
2754 constexpr int kTouchId1 = 1;
2755 constexpr int kTouchId2 = 2;
2756
2757 // Dispatches a long press event at the event generators current location.
2758 // Long press is one way to start dragging in splitview.
2759 auto dispatch_long_press = [this]() {
2760 ui::GestureEventDetails event_details(ui::ET_GESTURE_LONG_PRESS);
2761 const gfx::Point location = GetEventGenerator()->current_screen_location();
2762 ui::GestureEvent long_press(location.x(), location.y(), 0,
2763 ui::EventTimeForNow(), event_details);
2764 GetEventGenerator()->Dispatch(&long_press);
2765 };
2766
2767 // Verify that the bounds of the tapped window expand when touched.
2768 ui::test::EventGenerator* generator = GetEventGenerator();
2769 generator->set_current_screen_location(
2770 gfx::ToRoundedPoint(original_bounds1.CenterPoint()));
2771 generator->PressTouchId(kTouchId1);
2772 dispatch_long_press();
2773 EXPECT_GT(item1->target_bounds().width(), original_bounds1.width());
2774 EXPECT_GT(item1->target_bounds().height(), original_bounds1.height());
2775
2776 // Verify that attempting to touch the second window with a second finger does
2777 // nothing to the second window. The first window remains the window to be
2778 // dragged.
2779 generator->set_current_screen_location(
2780 gfx::ToRoundedPoint(original_bounds2.CenterPoint()));
2781 generator->PressTouchId(kTouchId2);
2782 dispatch_long_press();
2783 EXPECT_GT(item1->target_bounds().width(), original_bounds1.width());
2784 EXPECT_GT(item1->target_bounds().height(), original_bounds1.height());
2785 EXPECT_EQ(item2->target_bounds(), original_bounds2);
2786
2787 // Verify the first window moves on drag.
2788 gfx::PointF last_center_point = item1->target_bounds().CenterPoint();
2789 generator->MoveTouchIdBy(kTouchId1, 40, 40);
2790 EXPECT_NE(last_center_point, item1->target_bounds().CenterPoint());
2791 EXPECT_EQ(original_bounds2.CenterPoint(),
2792 item2->target_bounds().CenterPoint());
2793
2794 // Verify the first window moves on drag, even if we switch to a second
2795 // finger.
2796 last_center_point = item1->target_bounds().CenterPoint();
2797 generator->ReleaseTouchId(kTouchId2);
2798 generator->PressTouchId(kTouchId2);
2799 generator->MoveTouchIdBy(kTouchId2, 40, 40);
2800 EXPECT_NE(last_center_point, item1->target_bounds().CenterPoint());
2801 EXPECT_EQ(original_bounds2.CenterPoint(),
2802 item2->target_bounds().CenterPoint());
2803 }
2804
2805 // Verify that shadows on windows disappear for the duration of overview mode.
TEST_P(OverviewSessionTest,ShadowDisappearsInOverview)2806 TEST_P(OverviewSessionTest, ShadowDisappearsInOverview) {
2807 std::unique_ptr<aura::Window> window(CreateTestWindow());
2808
2809 // Verify that the shadow is initially visible.
2810 ::wm::ShadowController* shadow_controller = Shell::Get()->shadow_controller();
2811 EXPECT_TRUE(shadow_controller->IsShadowVisibleForWindow(window.get()));
2812
2813 // Verify that the shadow is invisible after entering overview mode.
2814 ToggleOverview();
2815 EXPECT_FALSE(shadow_controller->IsShadowVisibleForWindow(window.get()));
2816
2817 // Verify that the shadow is visible again after exiting overview mode.
2818 ToggleOverview();
2819 EXPECT_TRUE(shadow_controller->IsShadowVisibleForWindow(window.get()));
2820 }
2821
2822 // Verify that PIP windows will be excluded from the overview, but not hidden.
TEST_P(OverviewSessionTest,PipWindowShownButExcludedFromOverview)2823 TEST_P(OverviewSessionTest, PipWindowShownButExcludedFromOverview) {
2824 std::unique_ptr<aura::Window> pip_window(
2825 CreateTestWindow(gfx::Rect(200, 200)));
2826 WindowState* window_state = WindowState::Get(pip_window.get());
2827 const WMEvent enter_pip(WM_EVENT_PIP);
2828 window_state->OnWMEvent(&enter_pip);
2829
2830 // Enter overview.
2831 ToggleOverview();
2832
2833 // PIP window should be visible but not in the overview.
2834 EXPECT_TRUE(pip_window->IsVisible());
2835 EXPECT_FALSE(HighlightOverviewWindow(pip_window.get()));
2836 }
2837
2838 // Tests the PositionWindows function works as expected.
TEST_P(OverviewSessionTest,PositionWindows)2839 TEST_P(OverviewSessionTest, PositionWindows) {
2840 std::unique_ptr<aura::Window> window1(CreateTestWindow());
2841 std::unique_ptr<aura::Window> window2(CreateTestWindow());
2842 std::unique_ptr<aura::Window> window3(CreateTestWindow());
2843
2844 ToggleOverview();
2845 OverviewItem* item1 = GetOverviewItemForWindow(window1.get());
2846 OverviewItem* item2 = GetOverviewItemForWindow(window2.get());
2847 OverviewItem* item3 = GetOverviewItemForWindow(window3.get());
2848 const gfx::RectF bounds1 = item1->target_bounds();
2849 const gfx::RectF bounds2 = item2->target_bounds();
2850 const gfx::RectF bounds3 = item3->target_bounds();
2851
2852 // Verify that the bounds remain the same when calling PositionWindows again.
2853 overview_session()->PositionWindows(/*animate=*/false);
2854 EXPECT_EQ(bounds1, item1->target_bounds());
2855 EXPECT_EQ(bounds2, item2->target_bounds());
2856 EXPECT_EQ(bounds3, item3->target_bounds());
2857
2858 // Verify that |item2| and |item3| change bounds when calling PositionWindows
2859 // while ignoring |item1|.
2860 overview_session()->PositionWindows(/*animate=*/false, {item1});
2861 EXPECT_EQ(bounds1, item1->target_bounds());
2862 EXPECT_NE(bounds2, item2->target_bounds());
2863 EXPECT_NE(bounds3, item3->target_bounds());
2864
2865 // Return the windows to their original bounds.
2866 overview_session()->PositionWindows(/*animate=*/false);
2867
2868 // Verify that items that are animating before closing are ignored by
2869 // PositionWindows.
2870 item1->set_animating_to_close(true);
2871 item2->set_animating_to_close(true);
2872 overview_session()->PositionWindows(/*animate=*/false);
2873 EXPECT_EQ(bounds1, item1->target_bounds());
2874 EXPECT_EQ(bounds2, item2->target_bounds());
2875 EXPECT_NE(bounds3, item3->target_bounds());
2876 }
2877
2878 // Tests that overview mode is entered with kWindowDragged mode when a window is
2879 // dragged from the top of the screen. For the purposes of this test, we use a
2880 // browser window.
TEST_P(OverviewSessionTest,DraggingFromTopAnimation)2881 TEST_P(OverviewSessionTest, DraggingFromTopAnimation) {
2882 EnterTabletMode();
2883 std::unique_ptr<views::Widget> widget(CreateTestWidget(
2884 nullptr, desks_util::GetActiveDeskContainerId(), gfx::Rect(200, 200)));
2885 widget->GetNativeWindow()->SetProperty(aura::client::kTopViewInset, 20);
2886
2887 // Drag from the the top of the app to enter overview.
2888 ui::GestureEvent event(0, 0, 0, base::TimeTicks(),
2889 ui::GestureEventDetails(ui::ET_GESTURE_SCROLL_BEGIN));
2890 WindowState* window_state = WindowState::Get(widget->GetNativeWindow());
2891 window_state->CreateDragDetails(event.location_f(), HTCAPTION,
2892 ::wm::WINDOW_MOVE_SOURCE_TOUCH);
2893 auto drag_controller = std::make_unique<TabletModeWindowResizer>(
2894 window_state, std::make_unique<TabletModeBrowserWindowDragDelegate>());
2895 ui::Event::DispatcherApi dispatch_helper(&event);
2896 dispatch_helper.set_target(widget->GetNativeWindow());
2897 drag_controller->Drag(event.location_f(), event.flags());
2898
2899 ASSERT_TRUE(InOverviewSession());
2900 EXPECT_EQ(OverviewEnterExitType::kImmediateEnter,
2901 overview_session()->enter_exit_overview_type());
2902 }
2903
2904 // Tests the grid bounds are as expected with different shelf auto hide
2905 // behaviors and alignments.
TEST_P(OverviewSessionTest,GridBounds)2906 TEST_P(OverviewSessionTest, GridBounds) {
2907 UpdateDisplay("600x600");
2908 std::unique_ptr<aura::Window> window(CreateTestWindow(gfx::Rect(200, 200)));
2909
2910 Shelf* shelf = GetPrimaryShelf();
2911 shelf->SetAlignment(ShelfAlignment::kBottom);
2912 shelf->SetAutoHideBehavior(ShelfAutoHideBehavior::kNever);
2913
2914 // Test that with the bottom shelf, the grid should take up the entire display
2915 // minus the shelf area on the bottom regardless of auto hide behavior.
2916 const int shelf_size = ShelfConfig::Get()->shelf_size();
2917 ToggleOverview();
2918 EXPECT_EQ(gfx::Rect(0, 0, 600, 600 - shelf_size), GetGridBounds());
2919 ToggleOverview();
2920
2921 shelf->SetAutoHideBehavior(ShelfAutoHideBehavior::kAlways);
2922 ToggleOverview();
2923 EXPECT_EQ(gfx::Rect(0, 0, 600, 600 - shelf_size), GetGridBounds());
2924 ToggleOverview();
2925
2926 // Test that with the right shelf, the grid should take up the entire display
2927 // minus the shelf area on the right regardless of auto hide behavior.
2928 shelf->SetAlignment(ShelfAlignment::kRight);
2929 shelf->SetAutoHideBehavior(ShelfAutoHideBehavior::kNever);
2930 ToggleOverview();
2931 EXPECT_EQ(gfx::Rect(0, 0, 600 - shelf_size, 600), GetGridBounds());
2932 ToggleOverview();
2933
2934 shelf->SetAutoHideBehavior(ShelfAutoHideBehavior::kAlways);
2935 ToggleOverview();
2936 EXPECT_EQ(gfx::Rect(0, 0, 600 - shelf_size, 600), GetGridBounds());
2937 ToggleOverview();
2938 }
2939
2940 // Tests that windows that have a backdrop can still be tapped normally.
2941 // Regression test for crbug.com/938645.
TEST_P(OverviewSessionTest,SelectingWindowWithBackdrop)2942 TEST_P(OverviewSessionTest, SelectingWindowWithBackdrop) {
2943 std::unique_ptr<aura::Window> window(CreateTestWindow(gfx::Rect(500, 200)));
2944
2945 ToggleOverview();
2946 OverviewItem* item = GetOverviewItemForWindow(window.get());
2947 ASSERT_EQ(OverviewGridWindowFillMode::kLetterBoxed,
2948 item->GetWindowDimensionsType());
2949
2950 // Tap the target.
2951 GetEventGenerator()->set_current_screen_location(
2952 gfx::ToRoundedPoint(item->target_bounds().CenterPoint()));
2953 GetEventGenerator()->ClickLeftButton();
2954 EXPECT_FALSE(InOverviewSession());
2955 }
2956
TEST_P(OverviewSessionTest,ShelfAlignmentChangeWhileInOverview)2957 TEST_P(OverviewSessionTest, ShelfAlignmentChangeWhileInOverview) {
2958 Shelf* shelf = GetPrimaryShelf();
2959 shelf->SetAlignment(ShelfAlignment::kBottom);
2960 ToggleOverview();
2961 shelf->SetAlignment(ShelfAlignment::kRight);
2962 EXPECT_FALSE(InOverviewSession());
2963 }
2964
2965 namespace {
2966 class TestEventHandler : public ui::EventHandler {
2967 public:
2968 TestEventHandler() = default;
2969 ~TestEventHandler() override = default;
2970 // ui::EventHandler:
OnKeyEvent(ui::KeyEvent * event)2971 void OnKeyEvent(ui::KeyEvent* event) override {
2972 if (event->type() != ui::ET_KEY_PRESSED)
2973 return;
2974
2975 has_seen_event_ = true;
2976 event->SetHandled();
2977 event->StopPropagation();
2978 }
HasSeenEvent()2979 bool HasSeenEvent() { return has_seen_event_; }
Reset()2980 void Reset() { has_seen_event_ = false; }
2981
2982 private:
2983 bool has_seen_event_ = false;
2984 };
2985 } // namespace
2986
2987 // Test that keys are eaten when entering overview mode.
TEST_P(OverviewSessionTest,EatKeysDuringStartAnimation)2988 TEST_P(OverviewSessionTest, EatKeysDuringStartAnimation) {
2989 std::unique_ptr<aura::Window> test_window(CreateTestWindow());
2990 TestEventHandler test_event_handler;
2991 test_window->SetTargetHandler(&test_event_handler);
2992 test_window->Focus();
2993
2994 ui::ScopedAnimationDurationScaleMode animation_scale(
2995 ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
2996
2997 // Keys shouldn't be eaten by overview session normally.
2998 SendKey(ui::VKEY_A);
2999 ASSERT_TRUE(test_window->HasFocus());
3000 EXPECT_TRUE(test_event_handler.HasSeenEvent());
3001 test_event_handler.Reset();
3002
3003 // Keys should be eaten by overview session when entering overview mode.
3004 ToggleOverview();
3005 ASSERT_TRUE(Shell::Get()->overview_controller()->IsInStartAnimation());
3006 ASSERT_TRUE(test_window->HasFocus());
3007 SendKey(ui::VKEY_B);
3008 EXPECT_FALSE(test_event_handler.HasSeenEvent());
3009 EXPECT_TRUE(InOverviewSession());
3010
3011 WaitForOverviewEnterAnimation();
3012 ASSERT_FALSE(Shell::Get()->overview_controller()->IsInStartAnimation());
3013 EXPECT_FALSE(test_window->HasFocus());
3014
3015 ToggleOverview();
3016 SendKey(ui::VKEY_C);
3017 EXPECT_FALSE(InOverviewSession());
3018 EXPECT_TRUE(test_event_handler.HasSeenEvent());
3019 }
3020
3021 // Tests that in tablet mode, tapping on the background will go to home screen.
TEST_P(OverviewSessionTest,TapOnBackgroundGoToHome)3022 TEST_P(OverviewSessionTest, TapOnBackgroundGoToHome) {
3023 EnterTabletMode();
3024 UpdateDisplay("800x600");
3025 std::unique_ptr<aura::Window> window(CreateTestWindow());
3026 WindowState* window_state = WindowState::Get(window.get());
3027
3028 EXPECT_FALSE(window_state->IsMinimized());
3029 EXPECT_FALSE(Shell::Get()->home_screen_controller()->IsHomeScreenVisible());
3030 ToggleOverview();
3031 EXPECT_TRUE(InOverviewSession());
3032
3033 // Tap on the background. The tap location should be out of the tapping area
3034 // for back gesture. Otherwise, the touch event will be consumed and no
3035 // gesture event will be generated.
3036 ui::ScopedAnimationDurationScaleMode test_duration_mode(
3037 ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
3038 GetEventGenerator()->GestureTapAt(
3039 gfx::Point(BackGestureEventHandler::kStartGoingBackLeftEdgeInset, 10));
3040 ShellTestApi().WaitForOverviewAnimationState(
3041 OverviewAnimationState::kExitAnimationComplete);
3042
3043 EXPECT_FALSE(InOverviewSession());
3044 EXPECT_TRUE(window_state->IsMinimized());
3045 EXPECT_TRUE(Shell::Get()->home_screen_controller()->IsHomeScreenVisible());
3046 }
3047
3048 // Tests that in tablet mode, tapping on the background in split view mode will
3049 // be no-op.
TEST_P(OverviewSessionTest,TapOnBackgroundInSplitView)3050 TEST_P(OverviewSessionTest, TapOnBackgroundInSplitView) {
3051 EnterTabletMode();
3052 UpdateDisplay("800x600");
3053 std::unique_ptr<aura::Window> window1(CreateTestWindow());
3054
3055 std::unique_ptr<aura::Window> window2(CreateTestWindow());
3056
3057 EXPECT_FALSE(Shell::Get()->home_screen_controller()->IsHomeScreenVisible());
3058 ToggleOverview();
3059 EXPECT_TRUE(InOverviewSession());
3060
3061 split_view_controller()->SnapWindow(window2.get(),
3062 SplitViewController::RIGHT);
3063 EXPECT_TRUE(split_view_controller()->InSplitViewMode());
3064
3065 // Tap on the background.
3066 GetEventGenerator()->GestureTapAt(gfx::Point(10, 10));
3067
3068 EXPECT_TRUE(InOverviewSession());
3069 EXPECT_FALSE(Shell::Get()->home_screen_controller()->IsHomeScreenVisible());
3070 EXPECT_TRUE(split_view_controller()->InSplitViewMode());
3071 }
3072
3073 // Tests starting the overview session using kFadeInEnter type.
TEST_P(OverviewSessionTest,FadeIn)3074 TEST_P(OverviewSessionTest, FadeIn) {
3075 EnterTabletMode();
3076 // Create a minimized window.
3077 std::unique_ptr<aura::Window> window = CreateTestWindow();
3078 WindowState::Get(window.get())->Minimize();
3079
3080 ui::ScopedAnimationDurationScaleMode test_duration_mode(
3081 ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
3082
3083 ToggleOverview(OverviewEnterExitType::kFadeInEnter);
3084 ASSERT_TRUE(InOverviewSession());
3085
3086 OverviewItem* item = GetOverviewItemForWindow(window.get());
3087
3088 // Verify that the item widget's transform is not animated as part of the
3089 // animation.
3090 views::Widget* widget = item->item_widget();
3091 EXPECT_FALSE(widget->GetLayer()->GetAnimator()->IsAnimatingProperty(
3092 ui::LayerAnimationElement::TRANSFORM));
3093
3094 // Opacity should be animated to full opacity.
3095 EXPECT_EQ(1.0f, widget->GetLayer()->GetTargetOpacity());
3096 EXPECT_TRUE(widget->GetLayer()->GetAnimator()->IsAnimatingProperty(
3097 ui::LayerAnimationElement::OPACITY));
3098
3099 // Validate item bounds are within the grid.
3100 const gfx::Rect bounds = gfx::ToEnclosedRect(item->target_bounds());
3101 EXPECT_TRUE(GetGridBounds().Contains(bounds));
3102
3103 // Header is expected to be shown immediately.
3104 EXPECT_EQ(
3105 1.0f,
3106 item->overview_item_view()->header_view()->layer()->GetTargetOpacity());
3107
3108 EXPECT_EQ(OverviewEnterExitType::kFadeInEnter,
3109 overview_session()->enter_exit_overview_type());
3110 }
3111
3112 // Tests exiting the overview session using kFadeOutExit type.
TEST_P(OverviewSessionTest,FadeOutExit)3113 TEST_P(OverviewSessionTest, FadeOutExit) {
3114 EnterTabletMode();
3115 // Create a test window.
3116 std::unique_ptr<views::Widget> test_widget(CreateTestWidget());
3117 ToggleOverview();
3118 ASSERT_TRUE(InOverviewSession());
3119 EXPECT_FALSE(test_widget->IsMinimized());
3120
3121 ui::ScopedAnimationDurationScaleMode test_duration_mode(
3122 ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
3123
3124 // Grab the item widget before the session starts shutting down. The widget
3125 // should outlive the session, at least until the animations are done - given
3126 // that NON_ZERO_DURATION animation duration scale, it should be safe to
3127 // dereference the widget pointer immediately (synchronously) after the
3128 // session ends.
3129 OverviewItem* item = GetOverviewItemForWindow(test_widget->GetNativeWindow());
3130 views::Widget* grid_item_widget = item->item_widget();
3131 gfx::Rect item_bounds = grid_item_widget->GetWindowBoundsInScreen();
3132
3133 ToggleOverview(OverviewEnterExitType::kFadeOutExit);
3134 ASSERT_FALSE(InOverviewSession());
3135
3136 // The test window should be minimized as overview fade out exit starts.
3137 EXPECT_TRUE(test_widget->IsMinimized());
3138
3139 // Verify that the item widget's transform is not animated as part of the
3140 // animation, and that item widget bounds are not changed after minimizing the
3141 // window.
3142 EXPECT_FALSE(grid_item_widget->GetLayer()->GetAnimator()->IsAnimatingProperty(
3143 ui::LayerAnimationElement::TRANSFORM));
3144 EXPECT_EQ(item_bounds, grid_item_widget->GetWindowBoundsInScreen());
3145
3146 // Opacity should be animated to zero opacity.
3147 EXPECT_EQ(0.0f, grid_item_widget->GetLayer()->GetTargetOpacity());
3148 EXPECT_TRUE(grid_item_widget->GetLayer()->GetAnimator()->IsAnimatingProperty(
3149 ui::LayerAnimationElement::OPACITY));
3150 }
3151
3152 // Tests that accessibility overrides are set as expected on overview related
3153 // widgets.
TEST_P(OverviewSessionTest,AccessibilityFocusAnnotator)3154 TEST_P(OverviewSessionTest, AccessibilityFocusAnnotator) {
3155 auto window3 = CreateTestWindow(gfx::Rect(100, 100));
3156 auto window2 = CreateTestWindow(gfx::Rect(100, 100));
3157 auto window1 = CreateTestWindow(gfx::Rect(100, 100));
3158
3159 ToggleOverview();
3160 WaitForOverviewEnterAnimation();
3161
3162 auto* focus_widget = views::Widget::GetWidgetForNativeWindow(
3163 GetOverviewSession()->GetOverviewFocusWindow());
3164 DCHECK(focus_widget);
3165
3166 OverviewGrid* grid = GetOverviewSession()->grid_list()[0].get();
3167 auto* desk_widget = const_cast<views::Widget*>(grid->desks_widget());
3168 DCHECK(desk_widget);
3169
3170 // Overview items are in MRU order, so the expected order in the grid list is
3171 // the reverse creation order.
3172 auto* item_widget1 = GetOverviewItemForWindow(window1.get())->item_widget();
3173 auto* item_widget2 = GetOverviewItemForWindow(window2.get())->item_widget();
3174 auto* item_widget3 = GetOverviewItemForWindow(window3.get())->item_widget();
3175
3176 // Helper that takes in a current widget and checks if the accessibility next
3177 // and previous focus widgets match the given.
3178 auto check_a11y_overrides = [](const std::string& id, views::Widget* widget,
3179 views::Widget* expected_previous,
3180 views::Widget* expected_next) -> void {
3181 SCOPED_TRACE(id);
3182 views::View* contents_view = widget->GetContentsView();
3183 views::ViewAccessibility& view_accessibility =
3184 contents_view->GetViewAccessibility();
3185 EXPECT_EQ(expected_previous, view_accessibility.GetPreviousFocus());
3186 EXPECT_EQ(expected_next, view_accessibility.GetNextFocus());
3187 };
3188
3189 // Order should be [focus_widget, desk_widget, item_widget1, item_widget2,
3190 // item_widget3].
3191 check_a11y_overrides("focus", focus_widget, item_widget3, desk_widget);
3192 check_a11y_overrides("desk", desk_widget, focus_widget, item_widget1);
3193 check_a11y_overrides("item1", item_widget1, desk_widget, item_widget2);
3194 check_a11y_overrides("item2", item_widget2, item_widget1, item_widget3);
3195 check_a11y_overrides("item3", item_widget3, item_widget2, focus_widget);
3196
3197 // Remove |window2|. The new order should be [focus_widget, desk_widget,
3198 // item_widget1, item_widget3].
3199 window2.reset();
3200 check_a11y_overrides("focus", focus_widget, item_widget3, desk_widget);
3201 check_a11y_overrides("desk", desk_widget, focus_widget, item_widget1);
3202 check_a11y_overrides("item1", item_widget1, desk_widget, item_widget3);
3203 check_a11y_overrides("item3", item_widget3, item_widget1, focus_widget);
3204 }
3205
3206 // Tests that removing a transient child during overview does not result in a
3207 // crash when exiting overview.
TEST_P(OverviewSessionTest,RemoveTransientNoCrash)3208 TEST_P(OverviewSessionTest, RemoveTransientNoCrash) {
3209 auto child = CreateTestWindow();
3210 auto parent = CreateTestWindow();
3211 wm::AddTransientChild(parent.get(), child.get());
3212
3213 ToggleOverview();
3214 wm::RemoveTransientChild(parent.get(), child.get());
3215 ToggleOverview();
3216 }
3217
3218 class TabletModeOverviewSessionTest : public OverviewSessionTest {
3219 public:
3220 TabletModeOverviewSessionTest() = default;
3221 ~TabletModeOverviewSessionTest() override = default;
3222
3223 TabletModeOverviewSessionTest(const TabletModeOverviewSessionTest&) = delete;
3224 TabletModeOverviewSessionTest& operator=(
3225 const TabletModeOverviewSessionTest&) = delete;
3226
SetUp()3227 void SetUp() override {
3228 OverviewSessionTest::SetUp();
3229 EnterTabletMode();
3230 }
3231
split_view_controller()3232 SplitViewController* split_view_controller() {
3233 return SplitViewController::Get(Shell::GetPrimaryRootWindow());
3234 }
3235
3236 protected:
GenerateScrollSequence(const gfx::Point & start,const gfx::Point & end)3237 void GenerateScrollSequence(const gfx::Point& start, const gfx::Point& end) {
3238 GetEventGenerator()->GestureScrollSequence(
3239 start, end, base::TimeDelta::FromMilliseconds(100), 1000);
3240 }
3241
DispatchLongPress(OverviewItem * item)3242 void DispatchLongPress(OverviewItem* item) {
3243 ui::TouchEvent long_press(
3244 ui::ET_GESTURE_LONG_PRESS,
3245 gfx::ToRoundedPoint(item->target_bounds().CenterPoint()),
3246 base::TimeTicks::Now(),
3247 ui::PointerDetails(ui::EventPointerType::kTouch));
3248 GetEventGenerator()->Dispatch(&long_press);
3249 }
3250
3251 // Creates |n| test windows. They are created in reverse order, so that the
3252 // first window in the vector is the MRU window.
CreateTestWindows(int n)3253 std::vector<std::unique_ptr<aura::Window>> CreateTestWindows(int n) {
3254 std::vector<std::unique_ptr<aura::Window>> windows(n);
3255 for (int i = n - 1; i >= 0; --i)
3256 windows[i] = CreateTestWindow();
3257 return windows;
3258 }
3259 };
3260
3261 // Tests that windows are in proper positions in the new overview layout.
TEST_P(TabletModeOverviewSessionTest,CheckNewLayoutWindowPositions)3262 TEST_P(TabletModeOverviewSessionTest, CheckNewLayoutWindowPositions) {
3263 auto windows = CreateTestWindows(6);
3264 ToggleOverview();
3265 ASSERT_TRUE(InOverviewSession());
3266
3267 OverviewItem* item1 = GetOverviewItemForWindow(windows[0].get());
3268 OverviewItem* item2 = GetOverviewItemForWindow(windows[1].get());
3269 OverviewItem* item3 = GetOverviewItemForWindow(windows[2].get());
3270 OverviewItem* item4 = GetOverviewItemForWindow(windows[3].get());
3271
3272 const gfx::RectF item1_bounds = item1->target_bounds();
3273 const gfx::RectF item2_bounds = item2->target_bounds();
3274 const gfx::RectF item3_bounds = item3->target_bounds();
3275 const gfx::RectF item4_bounds = item4->target_bounds();
3276
3277 // |window1| should be in the top left position. |window2| should be directly
3278 // below |window1|, thus sharing the same x-value but not the same y-value.
3279 EXPECT_EQ(item1_bounds.x(), item2_bounds.x());
3280 EXPECT_LT(item1_bounds.y(), item2_bounds.y());
3281 // |window3| should be directly right of |window1|, thus sharing the same
3282 // y-value, but not the same x-value.
3283 EXPECT_LT(item1_bounds.x(), item3_bounds.x());
3284 EXPECT_EQ(item1_bounds.y(), item3_bounds.y());
3285 // |window4| should be directly right of |window2| and directly below
3286 // |window3|.
3287 EXPECT_LT(item2_bounds.x(), item4_bounds.x());
3288 EXPECT_EQ(item2_bounds.y(), item4_bounds.y());
3289 EXPECT_EQ(item3_bounds.x(), item4_bounds.x());
3290 EXPECT_LT(item3_bounds.y(), item4_bounds.y());
3291 }
3292
TEST_P(TabletModeOverviewSessionTest,CheckOffscreenWindows)3293 TEST_P(TabletModeOverviewSessionTest, CheckOffscreenWindows) {
3294 auto windows = CreateTestWindows(8);
3295 ToggleOverview();
3296 ASSERT_TRUE(InOverviewSession());
3297
3298 OverviewItem* item0 = GetOverviewItemForWindow(windows[0].get());
3299 OverviewItem* item1 = GetOverviewItemForWindow(windows[1].get());
3300 OverviewItem* item6 = GetOverviewItemForWindow(windows[6].get());
3301 OverviewItem* item7 = GetOverviewItemForWindow(windows[7].get());
3302
3303 const gfx::RectF screen_bounds(GetGridBounds());
3304 const gfx::RectF item0_bounds = item0->target_bounds();
3305 const gfx::RectF item1_bounds = item1->target_bounds();
3306 const gfx::RectF item6_bounds = item6->target_bounds();
3307 const gfx::RectF item7_bounds = item7->target_bounds();
3308
3309 // |item6| should be in the same row of windows as |item0|, but offscreen
3310 // (one screen length away).
3311 EXPECT_FALSE(screen_bounds.Contains(item6_bounds));
3312 EXPECT_EQ(item0_bounds.y(), item6_bounds.y());
3313 // |item7| should be in the same row of windows as |item1|, but offscreen
3314 // and below |item6|.
3315 EXPECT_FALSE(screen_bounds.Contains(item7_bounds));
3316 EXPECT_EQ(item1_bounds.y(), item7_bounds.y());
3317 EXPECT_LT(item6_bounds.y(), item7_bounds.y());
3318 }
3319
3320 // Tests to see if windows are not shifted if all already available windows
3321 // fit on screen.
TEST_P(TabletModeOverviewSessionTest,CheckNoOverviewItemShift)3322 TEST_P(TabletModeOverviewSessionTest, CheckNoOverviewItemShift) {
3323 auto windows = CreateTestWindows(4);
3324 ToggleOverview();
3325 ASSERT_TRUE(InOverviewSession());
3326
3327 OverviewItem* item0 = GetOverviewItemForWindow(windows[0].get());
3328 const gfx::RectF before_shift_bounds = item0->target_bounds();
3329
3330 GenerateScrollSequence(gfx::Point(100, 50), gfx::Point(0, 50));
3331 EXPECT_EQ(before_shift_bounds, item0->target_bounds());
3332 }
3333
3334 // Tests to see if windows are shifted if at least one window is
3335 // partially/completely positioned offscreen.
TEST_P(TabletModeOverviewSessionTest,CheckOverviewItemShift)3336 TEST_P(TabletModeOverviewSessionTest, CheckOverviewItemShift) {
3337 auto windows = CreateTestWindows(7);
3338 ToggleOverview();
3339 ASSERT_TRUE(InOverviewSession());
3340
3341 OverviewItem* item0 = GetOverviewItemForWindow(windows[0].get());
3342 const gfx::RectF before_shift_bounds = item0->target_bounds();
3343
3344 GenerateScrollSequence(gfx::Point(100, 50), gfx::Point(0, 50));
3345 EXPECT_LT(item0->target_bounds(), before_shift_bounds);
3346 }
3347
3348 // Tests to see if windows remain in bounds after scrolling extremely far.
TEST_P(TabletModeOverviewSessionTest,CheckOverviewItemScrollingBounds)3349 TEST_P(TabletModeOverviewSessionTest, CheckOverviewItemScrollingBounds) {
3350 auto windows = CreateTestWindows(8);
3351 ToggleOverview();
3352 ASSERT_TRUE(InOverviewSession());
3353
3354 // Scroll an extreme amount to see if windows on the far left are still in
3355 // bounds. First, align the left-most window (|windows[0]|) to the left-hand
3356 // bound and store the item's location. Then, scroll a far amount and check to
3357 // see if the item moved at all.
3358 OverviewItem* leftmost_window = GetOverviewItemForWindow(windows[0].get());
3359
3360 GenerateScrollSequence(
3361 gfx::Point(BackGestureEventHandler::kStartGoingBackLeftEdgeInset + 5, 50),
3362 gfx::Point(5000, 50));
3363 const gfx::RectF left_bounds = leftmost_window->target_bounds();
3364 GenerateScrollSequence(
3365 gfx::Point(BackGestureEventHandler::kStartGoingBackLeftEdgeInset + 5, 50),
3366 gfx::Point(5000, 50));
3367 EXPECT_EQ(left_bounds, leftmost_window->target_bounds());
3368
3369 // Scroll an extreme amount to see if windows on the far right are still in
3370 // bounds. First, align the right-most window (|windows[7]|) to the right-hand
3371 // bound and store the item's location. Then, scroll a far amount and check to
3372 // see if the item moved at all.
3373 OverviewItem* rightmost_window = GetOverviewItemForWindow(windows[7].get());
3374 GenerateScrollSequence(gfx::Point(5000, 50), gfx::Point(0, 50));
3375 const gfx::RectF right_bounds = rightmost_window->target_bounds();
3376 GenerateScrollSequence(gfx::Point(5000, 50), gfx::Point(0, 50));
3377 EXPECT_EQ(right_bounds, rightmost_window->target_bounds());
3378 }
3379
3380 // Tests the windows are stacked correctly when entering or exiting splitview
3381 // while the new overivew layout is enabled.
TEST_P(TabletModeOverviewSessionTest,StackingOrderSplitviewWindow)3382 TEST_P(TabletModeOverviewSessionTest, StackingOrderSplitviewWindow) {
3383 std::unique_ptr<aura::Window> window1 = CreateTestWindow();
3384 std::unique_ptr<aura::Window> window2 = CreateUnsnappableWindow();
3385 std::unique_ptr<aura::Window> window3 = CreateTestWindow();
3386
3387 ToggleOverview();
3388 ASSERT_TRUE(InOverviewSession());
3389
3390 // Snap |window1| to the left and exit overview. |window3| should have higher
3391 // z-order now, since it is the MRU window.
3392 split_view_controller()->SnapWindow(window1.get(), SplitViewController::LEFT);
3393 ToggleOverview();
3394 ASSERT_EQ(SplitViewController::State::kBothSnapped,
3395 split_view_controller()->state());
3396 ASSERT_GT(IndexOf(window3.get(), window3->parent()),
3397 IndexOf(window1.get(), window1->parent()));
3398
3399 // Test that on entering overview, |window3| is of a lower z-order, so that
3400 // when we scroll the grid, it will be seen under |window1|.
3401 ToggleOverview();
3402 EXPECT_LT(IndexOf(window3.get(), window3->parent()),
3403 IndexOf(window1.get(), window1->parent()));
3404
3405 // Test that |window2| has a cannot snap widget indicating that it cannot be
3406 // snapped, and that both |window2| and the widget are lower z-order than
3407 // |window1|.
3408 views::Widget* cannot_snap_widget =
3409 static_cast<views::Widget*>(GetOverviewItemForWindow(window2.get())
3410 ->cannot_snap_widget_for_testing());
3411 ASSERT_TRUE(cannot_snap_widget);
3412 aura::Window* cannot_snap_window = cannot_snap_widget->GetNativeWindow();
3413 ASSERT_EQ(window1->parent(), cannot_snap_window->parent());
3414 EXPECT_LT(IndexOf(window2.get(), window2->parent()),
3415 IndexOf(window1.get(), window1->parent()));
3416 EXPECT_LT(IndexOf(cannot_snap_window, cannot_snap_window->parent()),
3417 IndexOf(window1.get(), window1->parent()));
3418
3419 // Test that on exiting overview, |window3| becomes activated, so it returns
3420 // to being higher on the z-order than |window1|.
3421 ToggleOverview();
3422 EXPECT_GT(IndexOf(window3.get(), window3->parent()),
3423 IndexOf(window1.get(), window1->parent()));
3424 }
3425
3426 // Tests the windows are remain stacked underneath the split view window after
3427 // dragging or long pressing.
TEST_P(TabletModeOverviewSessionTest,StackingOrderAfterGestureEvent)3428 TEST_P(TabletModeOverviewSessionTest, StackingOrderAfterGestureEvent) {
3429 std::unique_ptr<aura::Window> window1 = CreateTestWindow();
3430 std::unique_ptr<aura::Window> window2 = CreateTestWindow();
3431
3432 ToggleOverview();
3433 ASSERT_TRUE(InOverviewSession());
3434 split_view_controller()->SnapWindow(window1.get(), SplitViewController::LEFT);
3435
3436 // Tests that if we long press, but cancel the event, the window stays stacked
3437 // under the snapped window.
3438 OverviewItem* item = GetOverviewItemForWindow(window2.get());
3439 const gfx::PointF item_center = item->target_bounds().CenterPoint();
3440 DispatchLongPress(item);
3441 ui::GestureEvent gesture_end(item_center.x(), item_center.y(), 0,
3442 ui::EventTimeForNow(),
3443 ui::GestureEventDetails(ui::ET_GESTURE_END));
3444 item->HandleGestureEvent(&gesture_end);
3445 EXPECT_GT(IndexOf(window1.get(), window1->parent()),
3446 IndexOf(window2.get(), window2->parent()));
3447
3448 // Tests that if we drag the window around, then release, the window also
3449 // stays stacked under the snapped window.
3450 ASSERT_TRUE(InOverviewSession());
3451 const gfx::Vector2dF delta(15.f, 15.f);
3452 DispatchLongPress(item);
3453 overview_session()->Drag(item, item_center + delta);
3454 overview_session()->CompleteDrag(item, item_center + delta);
3455 EXPECT_GT(IndexOf(window1.get(), window1->parent()),
3456 IndexOf(window2.get(), window2->parent()));
3457 }
3458
3459 // Test that scrolling occurs if started on top of a window using the window's
3460 // center-point as a start.
TEST_P(TabletModeOverviewSessionTest,HorizontalScrollingOnOverviewItem)3461 TEST_P(TabletModeOverviewSessionTest, HorizontalScrollingOnOverviewItem) {
3462 auto windows = CreateTestWindows(8);
3463 ToggleOverview();
3464 ASSERT_TRUE(InOverviewSession());
3465
3466 OverviewItem* leftmost_window = GetOverviewItemForWindow(windows[0].get());
3467 const gfx::Point topleft_window_center =
3468 gfx::ToRoundedPoint(leftmost_window->target_bounds().CenterPoint());
3469 const gfx::RectF left_bounds = leftmost_window->target_bounds();
3470
3471 GenerateScrollSequence(topleft_window_center, gfx::Point(-500, 50));
3472 EXPECT_LT(leftmost_window->target_bounds(), left_bounds);
3473 }
3474
3475 // A unique test class for testing flings in overview as those rely on observing
3476 // compositor animations which require a mock time task environment.
3477 class OverviewSessionFlingTest : public AshTestBase {
3478 public:
OverviewSessionFlingTest()3479 OverviewSessionFlingTest()
3480 : AshTestBase(base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
3481 ~OverviewSessionFlingTest() override = default;
3482
3483 OverviewSessionFlingTest(const OverviewSessionFlingTest&) = delete;
3484 OverviewSessionFlingTest& operator=(const OverviewSessionFlingTest&) = delete;
3485
3486 // AshTestBase:
SetUp()3487 void SetUp() override {
3488 AshTestBase::SetUp();
3489
3490 // Overview flinging is only available in tablet mode.
3491 base::RunLoop().RunUntilIdle();
3492 TabletModeControllerTestApi().EnterTabletMode();
3493 base::RunLoop().RunUntilIdle();
3494 }
3495 };
3496
TEST_F(OverviewSessionFlingTest,BasicFling)3497 TEST_F(OverviewSessionFlingTest, BasicFling) {
3498 std::vector<std::unique_ptr<aura::Window>> windows(16);
3499 for (int i = 15; i >= 0; --i)
3500 windows[i] = CreateTestWindow();
3501
3502 ToggleOverview();
3503 OverviewGrid* grid = GetOverviewSession()->grid_list()[0].get();
3504 OverviewGridEventHandler* grid_event_handler = grid->grid_event_handler();
3505
3506 OverviewItem* item = GetOverviewItemForWindow(windows[2].get());
3507 const gfx::Point item_center =
3508 gfx::ToRoundedPoint(item->target_bounds().CenterPoint());
3509
3510 // Create a scroll sequence which results in a fling.
3511 const gfx::Vector2d shift(-200, 0);
3512 GetEventGenerator()->GestureScrollSequence(
3513 item_center, item_center + shift, base::TimeDelta::FromMilliseconds(10),
3514 10);
3515
3516 ui::Compositor* const compositor =
3517 windows[0]->GetRootWindow()->layer()->GetCompositor();
3518 ui::DrawWaiterForTest::WaitForCompositingStarted(compositor);
3519 ASSERT_TRUE(grid_event_handler->IsFlingInProgressForTesting());
3520
3521 // Test that the scroll offset decreases as we advance the clock. Check the
3522 // scroll offset instead of the item bounds as there is an optimization which
3523 // does not update the item bounds of invisible elements. On some iterations,
3524 // there may not be enough time passed to decay the velocity so the scroll
3525 // offset will not change, but the overall change should be substantial.
3526 constexpr int kMaxLoops = 10;
3527 const float initial_scroll_offset = grid->scroll_offset();
3528 float previous_scroll_offset = initial_scroll_offset;
3529 for (int i = 0;
3530 i < kMaxLoops && grid_event_handler->IsFlingInProgressForTesting();
3531 ++i) {
3532 task_environment()->FastForwardBy(base::TimeDelta::FromMilliseconds(50));
3533 ui::DrawWaiterForTest::WaitForCompositingStarted(compositor);
3534
3535 float scroll_offset = grid->scroll_offset();
3536 EXPECT_LE(scroll_offset, previous_scroll_offset);
3537 previous_scroll_offset = scroll_offset;
3538 }
3539
3540 EXPECT_LT(grid->scroll_offset(), initial_scroll_offset - 100.f);
3541 }
3542
3543 // Tests that a vertical scroll sequence will close the window it is scrolled
3544 // on.
TEST_P(TabletModeOverviewSessionTest,VerticalScrollingOnOverviewItem)3545 TEST_P(TabletModeOverviewSessionTest, VerticalScrollingOnOverviewItem) {
3546 constexpr int kNumWidgets = 8;
3547 std::vector<std::unique_ptr<views::Widget>> widgets(kNumWidgets);
3548 for (int i = kNumWidgets - 1; i >= 0; --i)
3549 widgets[i] = CreateTestWidget();
3550 ToggleOverview();
3551 ASSERT_TRUE(InOverviewSession());
3552
3553 OverviewItem* leftmost_window =
3554 GetOverviewItemForWindow(widgets[0]->GetNativeWindow());
3555 const gfx::Point topleft_window_center =
3556 gfx::ToRoundedPoint(leftmost_window->target_bounds().CenterPoint());
3557 const gfx::Point end_point = topleft_window_center - gfx::Vector2d(0, 300);
3558
3559 GenerateScrollSequence(topleft_window_center, end_point);
3560 EXPECT_TRUE(widgets[0]->IsClosed());
3561 }
3562
3563 // Test that scrolling occurs if we hit the associated keyboard shortcut.
TEST_P(TabletModeOverviewSessionTest,CheckScrollingWithKeyboardShortcut)3564 TEST_P(TabletModeOverviewSessionTest, CheckScrollingWithKeyboardShortcut) {
3565 auto windows = CreateTestWindows(8);
3566 ToggleOverview();
3567 ASSERT_TRUE(InOverviewSession());
3568
3569 OverviewItem* leftmost_window = GetOverviewItemForWindow(windows[0].get());
3570 const gfx::RectF left_bounds = leftmost_window->target_bounds();
3571
3572 SendKey(ui::VKEY_RIGHT, ui::EF_CONTROL_DOWN);
3573 EXPECT_LT(leftmost_window->target_bounds(), left_bounds);
3574 }
3575
3576 // Test that tapping a window in overview closes overview mode.
TEST_P(TabletModeOverviewSessionTest,CheckWindowActivateOnTap)3577 TEST_P(TabletModeOverviewSessionTest, CheckWindowActivateOnTap) {
3578 base::UserActionTester user_action_tester;
3579 auto windows = CreateTestWindows(8);
3580 wm::ActivateWindow(windows[1].get());
3581
3582 ToggleOverview();
3583 ASSERT_TRUE(InOverviewSession());
3584
3585 // Tap on |windows[1]| to exit overview.
3586 GetEventGenerator()->GestureTapAt(
3587 GetTransformedTargetBounds(windows[1].get()).CenterPoint());
3588 EXPECT_EQ(
3589 0, user_action_tester.GetActionCount(kActiveWindowChangedFromOverview));
3590
3591 // |windows[1]| remains active. Click on it to exit overview.
3592 ASSERT_EQ(windows[1].get(), window_util::GetFocusedWindow());
3593 ToggleOverview();
3594 ClickWindow(windows[1].get());
3595 EXPECT_EQ(
3596 0, user_action_tester.GetActionCount(kActiveWindowChangedFromOverview));
3597 }
3598
TEST_P(TabletModeOverviewSessionTest,LayoutValidAfterRotation)3599 TEST_P(TabletModeOverviewSessionTest, LayoutValidAfterRotation) {
3600 UpdateDisplay("1366x768");
3601 display::test::ScopedSetInternalDisplayId set_internal(
3602 Shell::Get()->display_manager(),
3603 display::Screen::GetScreen()->GetPrimaryDisplay().id());
3604 auto windows = CreateTestWindows(7);
3605
3606 // Helper to determine whether a grid layout is valid. It is considered valid
3607 // if the left edge of the first item is close enough to the left edge of the
3608 // grid bounds and if the right edge of the last item is close enough to the
3609 // right edge of the grid bounds. Either of these being false would mean there
3610 // is a large padding which shouldn't be there.
3611 auto layout_valid = [&windows, this](int expected_padding) {
3612 OverviewItem* first_item = GetOverviewItemForWindow(windows.front().get());
3613 OverviewItem* last_item = GetOverviewItemForWindow(windows.back().get());
3614
3615 const gfx::Rect first_bounds =
3616 gfx::ToEnclosedRect(first_item->target_bounds());
3617 const gfx::Rect last_bounds =
3618 gfx::ToEnclosedRect(last_item->target_bounds());
3619
3620 const gfx::Rect grid_bounds = GetGridBounds();
3621 const bool first_bounds_valid =
3622 first_bounds.x() <= (grid_bounds.x() + expected_padding);
3623 const bool last_bounds_valid =
3624 last_bounds.right() >= (grid_bounds.right() - expected_padding);
3625 return first_bounds_valid && last_bounds_valid;
3626 };
3627
3628 // Enter overview and scroll to the edge of the grid. The layout should remain
3629 // valid.
3630 ToggleOverview();
3631 ASSERT_TRUE(InOverviewSession());
3632 // The expected padding should be the x position of the first item, before the
3633 // grid gets shifted.
3634 const int expected_padding =
3635 GetOverviewItemForWindow(windows.front().get())->target_bounds().x();
3636 GenerateScrollSequence(gfx::Point(1300, 10), gfx::Point(100, 10));
3637 EXPECT_TRUE(layout_valid(expected_padding));
3638
3639 // Tests that the layout is still valid after a couple rotations.
3640 ScreenOrientationControllerTestApi test_api(
3641 Shell::Get()->screen_orientation_controller());
3642 test_api.SetDisplayRotation(display::Display::ROTATE_90,
3643 display::Display::RotationSource::ACTIVE);
3644 EXPECT_TRUE(layout_valid(expected_padding));
3645
3646 test_api.SetDisplayRotation(display::Display::ROTATE_180,
3647 display::Display::RotationSource::ACTIVE);
3648 EXPECT_TRUE(layout_valid(expected_padding));
3649 }
3650
3651 // Tests that windows snap through long press and drag to left or right side of
3652 // the screen.
TEST_P(TabletModeOverviewSessionTest,DragOverviewWindowToSnap)3653 TEST_P(TabletModeOverviewSessionTest, DragOverviewWindowToSnap) {
3654 const gfx::Rect bounds(400, 400);
3655 std::unique_ptr<aura::Window> window1(CreateTestWindow(bounds));
3656 std::unique_ptr<aura::Window> window2(CreateTestWindow(bounds));
3657 std::unique_ptr<aura::Window> window3(CreateTestWindow(bounds));
3658
3659 ToggleOverview();
3660 ASSERT_TRUE(overview_controller()->InOverviewSession());
3661 ASSERT_FALSE(split_view_controller()->InSplitViewMode());
3662
3663 // Dispatches a long press event at the |overview_item1|'s current location to
3664 // start dragging in SplitView. Drags |overview_item1| to the left border of
3665 // the screen. SplitView should trigger and upon completing drag,
3666 // |overview_item1| should snap to the left.
3667 OverviewItem* overview_item1 = GetOverviewItemForWindow(window1.get());
3668 const gfx::PointF snap_left_location =
3669 gfx::PointF(GetGridBounds().left_center());
3670
3671 DispatchLongPress(overview_item1);
3672 overview_session()->Drag(
3673 overview_item1,
3674 gfx::PointF(overview_item1->target_bounds().left_center()));
3675 overview_session()->CompleteDrag(overview_item1, snap_left_location);
3676
3677 ASSERT_TRUE(split_view_controller()->InSplitViewMode());
3678 EXPECT_EQ(split_view_controller()->state(),
3679 SplitViewController::State::kLeftSnapped);
3680 EXPECT_EQ(split_view_controller()->left_window(), window1.get());
3681
3682 // Dispatches a long press event at the |overview_item2|'s current location to
3683 // start dragging in SplitView. Drags |overview_item2| to the right border of
3684 // the screen. Upon completing drag, |overview_item2| should snap to the
3685 // right.
3686 OverviewItem* overview_item2 = GetOverviewItemForWindow(window2.get());
3687 const gfx::PointF snap_right_location =
3688 gfx::PointF(GetGridBounds().right_center());
3689
3690 DispatchLongPress(overview_item2);
3691 overview_session()->Drag(
3692 overview_item2,
3693 gfx::PointF(overview_item2->target_bounds().right_center()));
3694 overview_session()->CompleteDrag(overview_item2, snap_right_location);
3695
3696 EXPECT_FALSE(InOverviewSession());
3697 EXPECT_TRUE(split_view_controller()->InSplitViewMode());
3698 EXPECT_EQ(split_view_controller()->state(),
3699 SplitViewController::State::kBothSnapped);
3700 EXPECT_EQ(split_view_controller()->right_window(), window2.get());
3701 }
3702
3703 // Verify that if the window item has been dragged enough vertically, the window
3704 // will be closed.
TEST_P(TabletModeOverviewSessionTest,DragToClose)3705 TEST_P(TabletModeOverviewSessionTest, DragToClose) {
3706 // This test requires a widget.
3707 std::unique_ptr<views::Widget> widget(CreateTestWidget());
3708
3709 ToggleOverview();
3710 ASSERT_TRUE(overview_controller()->InOverviewSession());
3711
3712 OverviewItem* item = GetOverviewItemForWindow(widget->GetNativeWindow());
3713 const gfx::PointF start = item->target_bounds().CenterPoint();
3714 ASSERT_TRUE(item);
3715
3716 // This drag has not covered enough distance, so the widget is not closed and
3717 // we remain in overview mode.
3718 overview_session()->InitiateDrag(item, start, /*is_touch_dragging=*/true);
3719 overview_session()->Drag(item, start + gfx::Vector2dF(0, 80));
3720 overview_session()->CompleteDrag(item, start + gfx::Vector2dF(0, 80));
3721 ASSERT_TRUE(overview_session());
3722
3723 // Verify that the second drag has enough vertical distance, so the widget
3724 // will be closed and overview mode will be exited.
3725 overview_session()->InitiateDrag(item, start, /*is_touch_dragging=*/true);
3726 overview_session()->Drag(item, start + gfx::Vector2dF(0, 180));
3727 overview_session()->CompleteDrag(item, start + gfx::Vector2dF(0, 180));
3728 base::RunLoop().RunUntilIdle();
3729 EXPECT_FALSE(overview_session());
3730 EXPECT_TRUE(widget->IsClosed());
3731 }
3732
3733 // Verify that if the window item has been flung enough vertically, the window
3734 // will be closed.
TEST_P(TabletModeOverviewSessionTest,FlingToClose)3735 TEST_P(TabletModeOverviewSessionTest, FlingToClose) {
3736 // This test requires a widget.
3737 std::unique_ptr<views::Widget> widget(CreateTestWidget());
3738
3739 ToggleOverview();
3740 ASSERT_TRUE(overview_controller()->InOverviewSession());
3741 EXPECT_EQ(1u, overview_session()->grid_list()[0]->size());
3742
3743 OverviewItem* item = GetOverviewItemForWindow(widget->GetNativeWindow());
3744 const gfx::PointF start = item->target_bounds().CenterPoint();
3745 ASSERT_TRUE(item);
3746
3747 // Verify that items flung horizontally do not close the item.
3748 overview_session()->InitiateDrag(item, start, /*is_touch_dragging=*/true);
3749 overview_session()->Drag(item, start + gfx::Vector2dF(0, 50));
3750 overview_session()->Fling(item, start, 2500, 0);
3751 ASSERT_TRUE(overview_session());
3752
3753 // Verify that items flung vertically but without enough velocity do not
3754 // close the item.
3755 overview_session()->InitiateDrag(item, start, /*is_touch_dragging=*/true);
3756 overview_session()->Drag(item, start + gfx::Vector2dF(0, 50));
3757 overview_session()->Fling(item, start, 0, 1500);
3758 ASSERT_TRUE(overview_session());
3759
3760 // Verify that flinging the item closes it, and since it is the last item in
3761 // overview mode, overview mode is exited.
3762 overview_session()->InitiateDrag(item, start, /*is_touch_dragging=*/true);
3763 overview_session()->Drag(item, start + gfx::Vector2dF(0, 50));
3764 overview_session()->Fling(item, start, 0, 2500);
3765 base::RunLoop().RunUntilIdle();
3766 EXPECT_FALSE(overview_session());
3767 EXPECT_TRUE(widget->IsClosed());
3768 }
3769
3770 // Tests that nudging occurs in the most basic case, which is we have one row
3771 // and one item which is about to be deleted by dragging. If the item is deleted
3772 // we still only have one row, so the other items should nudge while the item is
3773 // being dragged.
TEST_P(TabletModeOverviewSessionTest,BasicNudging)3774 TEST_P(TabletModeOverviewSessionTest, BasicNudging) {
3775 // Set up three equal windows, which take up one row on the overview grid.
3776 // When one of them is deleted we are still left with all the windows on one
3777 // row.
3778 std::unique_ptr<aura::Window> window1 = CreateTestWindow();
3779 std::unique_ptr<aura::Window> window2 = CreateTestWindow();
3780 std::unique_ptr<aura::Window> window3 = CreateTestWindow();
3781
3782 ToggleOverview();
3783 ASSERT_TRUE(overview_controller()->InOverviewSession());
3784
3785 OverviewItem* item1 = GetOverviewItemForWindow(window1.get());
3786 OverviewItem* item2 = GetOverviewItemForWindow(window2.get());
3787 OverviewItem* item3 = GetOverviewItemForWindow(window3.get());
3788
3789 const gfx::RectF item1_bounds = item1->target_bounds();
3790 const gfx::RectF item2_bounds = item2->target_bounds();
3791 const gfx::RectF item3_bounds = item3->target_bounds();
3792
3793 // Drag |item1| vertically. |item2| and |item3| bounds should change as they
3794 // should be nudging towards their final bounds.
3795 overview_session()->InitiateDrag(item1, item1_bounds.CenterPoint(),
3796 /*is_touch_dragging=*/true);
3797 overview_session()->Drag(item1,
3798 item1_bounds.CenterPoint() + gfx::Vector2dF(0, 160));
3799 EXPECT_NE(item2_bounds, item2->target_bounds());
3800 EXPECT_NE(item3_bounds, item3->target_bounds());
3801
3802 // Drag |item1| back to its start drag location and release, so that it does
3803 // not get deleted.
3804 overview_session()->Drag(item1, item1_bounds.CenterPoint());
3805 overview_session()->CompleteDrag(item1, item1_bounds.CenterPoint());
3806
3807 // Drag |item3| vertically. |item1| and |item2| bounds should change as they
3808 // should be nudging towards their final bounds.
3809 overview_session()->InitiateDrag(item3, item3_bounds.CenterPoint(),
3810 /*is_touch_dragging=*/true);
3811 overview_session()->Drag(item3,
3812 item3_bounds.CenterPoint() + gfx::Vector2dF(0, 160));
3813 EXPECT_NE(item1_bounds, item1->target_bounds());
3814 EXPECT_NE(item2_bounds, item2->target_bounds());
3815 }
3816
3817 // Tests that no nudging occurs when the number of rows in overview mode change
3818 // if the item to be deleted results in the overview grid to change number of
3819 // rows.
TEST_P(TabletModeOverviewSessionTest,NoNudgingWhenNumRowsChange)3820 TEST_P(TabletModeOverviewSessionTest, NoNudgingWhenNumRowsChange) {
3821 // Set up four equal windows, which would split into two rows in overview
3822 // mode. Removing one window would leave us with three windows, which only
3823 // takes a single row in overview.
3824 std::unique_ptr<aura::Window> window1 = CreateTestWindow();
3825 std::unique_ptr<aura::Window> window2 = CreateTestWindow();
3826 std::unique_ptr<aura::Window> window3 = CreateTestWindow();
3827 std::unique_ptr<aura::Window> window4 = CreateTestWindow();
3828
3829 ToggleOverview();
3830 ASSERT_TRUE(overview_controller()->InOverviewSession());
3831
3832 OverviewItem* item1 = GetOverviewItemForWindow(window1.get());
3833 OverviewItem* item2 = GetOverviewItemForWindow(window2.get());
3834 OverviewItem* item3 = GetOverviewItemForWindow(window3.get());
3835 OverviewItem* item4 = GetOverviewItemForWindow(window4.get());
3836
3837 const gfx::RectF item1_bounds = item1->target_bounds();
3838 const gfx::RectF item2_bounds = item2->target_bounds();
3839 const gfx::RectF item3_bounds = item3->target_bounds();
3840 const gfx::RectF item4_bounds = item4->target_bounds();
3841
3842 // Drag |item1| past the drag to swipe threshold. None of the other window
3843 // bounds should change, as none of them should be nudged.
3844 overview_session()->InitiateDrag(item1, item1_bounds.CenterPoint(),
3845 /*is_touch_dragging=*/true);
3846 overview_session()->Drag(item1,
3847 item1_bounds.CenterPoint() + gfx::Vector2dF(0, 160));
3848 EXPECT_EQ(item2_bounds, item2->target_bounds());
3849 EXPECT_EQ(item3_bounds, item3->target_bounds());
3850 EXPECT_EQ(item4_bounds, item4->target_bounds());
3851 }
3852
3853 // Tests that no nudging occurs when the item to be deleted results in an item
3854 // from the previous row to drop down to the current row, thus causing the items
3855 // to the right of the item to be shifted right, which is visually unacceptable.
TEST_P(TabletModeOverviewSessionTest,NoNudgingWhenLastItemOnPreviousRowDrops)3856 TEST_P(TabletModeOverviewSessionTest, NoNudgingWhenLastItemOnPreviousRowDrops) {
3857 // Set up five equal windows, which would split into two rows in overview
3858 // mode. Removing one window would cause the rows to rearrange, with the third
3859 // item dropping down from the first row to the second row. Create the windows
3860 // backward so the the window indexs match the order seen in overview, as
3861 // overview windows are ordered by MRU.
3862 const int kWindows = 5;
3863 std::unique_ptr<aura::Window> windows[kWindows];
3864 for (int i = kWindows - 1; i >= 0; --i)
3865 windows[i] = CreateTestWindow();
3866
3867 ToggleOverview();
3868 ASSERT_TRUE(overview_controller()->InOverviewSession());
3869
3870 OverviewItem* items[kWindows];
3871 gfx::RectF item_bounds[kWindows];
3872 for (int i = 0; i < kWindows; ++i) {
3873 items[i] = GetOverviewItemForWindow(windows[i].get());
3874 item_bounds[i] = items[i]->target_bounds();
3875 }
3876
3877 // Drag the forth item past the drag to swipe threshold. None of the other
3878 // window bounds should change, as none of them should be nudged, because
3879 // deleting the fourth item will cause the third item to drop down from the
3880 // first row to the second.
3881 overview_session()->InitiateDrag(items[3], item_bounds[3].CenterPoint(),
3882 /*is_touch_dragging=*/true);
3883 overview_session()->Drag(
3884 items[3], item_bounds[3].CenterPoint() + gfx::Vector2dF(0, 160));
3885 EXPECT_EQ(item_bounds[0], items[0]->target_bounds());
3886 EXPECT_EQ(item_bounds[1], items[1]->target_bounds());
3887 EXPECT_EQ(item_bounds[2], items[2]->target_bounds());
3888 EXPECT_EQ(item_bounds[4], items[4]->target_bounds());
3889
3890 // Drag the fourth item back to its start drag location and release, so that
3891 // it does not get deleted.
3892 overview_session()->Drag(items[3], item_bounds[3].CenterPoint());
3893 overview_session()->CompleteDrag(items[3], item_bounds[3].CenterPoint());
3894
3895 // Drag the first item past the drag to swipe threshold. The second and third
3896 // items should nudge as expected as there is no item dropping down to their
3897 // row. The fourth and fifth items should not nudge as they are in a different
3898 // row than the first item.
3899 overview_session()->InitiateDrag(items[0], item_bounds[0].CenterPoint(),
3900 /*is_touch_dragging=*/true);
3901 overview_session()->Drag(
3902 items[0], item_bounds[0].CenterPoint() + gfx::Vector2dF(0, 160));
3903 EXPECT_NE(item_bounds[1], items[1]->target_bounds());
3904 EXPECT_NE(item_bounds[2], items[2]->target_bounds());
3905 EXPECT_EQ(item_bounds[3], items[3]->target_bounds());
3906 EXPECT_EQ(item_bounds[4], items[4]->target_bounds());
3907 }
3908
3909 // Tests that there is no crash when destroying a window during a nudge drag.
3910 // Regression test for https://crbug.com/997335.
TEST_P(TabletModeOverviewSessionTest,DestroyWindowDuringNudge)3911 TEST_P(TabletModeOverviewSessionTest, DestroyWindowDuringNudge) {
3912 std::unique_ptr<aura::Window> window1 = CreateTestWindow();
3913 std::unique_ptr<aura::Window> window2 = CreateTestWindow();
3914 std::unique_ptr<aura::Window> window3 = CreateTestWindow();
3915
3916 ToggleOverview();
3917 ASSERT_TRUE(overview_controller()->InOverviewSession());
3918
3919 OverviewItem* item = GetOverviewItemForWindow(window1.get());
3920 const gfx::PointF item_center = item->target_bounds().CenterPoint();
3921
3922 // Drag |item1| vertically to start nudging.
3923 overview_session()->InitiateDrag(item, item_center,
3924 /*is_touch_dragging=*/true);
3925 overview_session()->Drag(item, item_center + gfx::Vector2dF(0, 160));
3926
3927 // Destroy |window2| and |window3|,then keep dragging. There should be no
3928 // crash.
3929 window2.reset();
3930 window3.reset();
3931 overview_session()->Drag(item, item_center + gfx::Vector2dF(0, 260));
3932 }
3933
TEST_P(TabletModeOverviewSessionTest,MultiTouch)3934 TEST_P(TabletModeOverviewSessionTest, MultiTouch) {
3935 const gfx::Rect bounds(400, 400);
3936 std::unique_ptr<aura::Window> window1(CreateTestWindow(bounds));
3937 std::unique_ptr<aura::Window> window2(CreateTestWindow(bounds));
3938
3939 ToggleOverview();
3940 ASSERT_TRUE(overview_controller()->InOverviewSession());
3941
3942 // Dispatches a long press event to start drag mode.
3943 OverviewItem* item = GetOverviewItemForWindow(window1.get());
3944 DispatchLongPress(item);
3945 overview_session()->Drag(item, gfx::PointF(10.f, 500.f));
3946 const gfx::Rect item_bounds = item->GetWindow()->GetBoundsInScreen();
3947
3948 // Tap on a point on the wallpaper. Normally this would exit overview, but not
3949 // while a drag is underway.
3950 GetEventGenerator()->set_current_screen_location(gfx::Point(10, 10));
3951 GetEventGenerator()->PressTouch();
3952 GetEventGenerator()->ReleaseTouch();
3953 ASSERT_TRUE(overview_controller()->InOverviewSession());
3954 EXPECT_EQ(item_bounds, item->GetWindow()->GetBoundsInScreen());
3955
3956 // Long press on another item, the bounds of both items should be unchanged.
3957 OverviewItem* item2 = GetOverviewItemForWindow(window2.get());
3958 const gfx::Rect item2_bounds = item2->GetWindow()->GetBoundsInScreen();
3959 DispatchLongPress(item2);
3960 EXPECT_EQ(item_bounds, item->GetWindow()->GetBoundsInScreen());
3961 EXPECT_EQ(item2_bounds, item2->GetWindow()->GetBoundsInScreen());
3962
3963 // Clicking on a point on the wallpaper should still exit overview.
3964 GetEventGenerator()->set_current_screen_location(gfx::Point(10, 10));
3965 GetEventGenerator()->ClickLeftButton();
3966 EXPECT_FALSE(overview_controller()->InOverviewSession());
3967 }
3968
3969 // Tests that when exiting overview in a way that causes windows to minimize,
3970 // rounded corners are removed, otherwise they will be visible after
3971 // unminimizing. Regression test for https://crbug.com/1146240.
TEST_P(TabletModeOverviewSessionTest,MinimizedRoundedCorners)3972 TEST_P(TabletModeOverviewSessionTest, MinimizedRoundedCorners) {
3973 const gfx::Rect bounds(400, 400);
3974 std::unique_ptr<aura::Window> window(CreateTestWindow(bounds));
3975
3976 // Enter overview. Spin the run loop since rounded corners are applied on a
3977 // post task.
3978 ToggleOverview();
3979 base::RunLoop().RunUntilIdle();
3980 ASSERT_TRUE(overview_controller()->InOverviewSession());
3981
3982 // Tap on a point on the wallpaper to minimize the window and exit overview.
3983 GetEventGenerator()->set_current_screen_location(gfx::Point(10, 10));
3984 GetEventGenerator()->ClickLeftButton();
3985
3986 // Tests that the window layer has rounded corners removed after exiting
3987 // overview.
3988 EXPECT_FALSE(overview_controller()->InOverviewSession());
3989 EXPECT_TRUE(WindowState::Get(window.get())->IsMinimized());
3990 EXPECT_EQ(gfx::RoundedCornersF(), window->layer()->rounded_corner_radii());
3991 }
3992
3993 // Test the split view and overview functionalities in tablet mode.
3994 class SplitViewOverviewSessionTest : public OverviewSessionTest {
3995 public:
3996 SplitViewOverviewSessionTest() = default;
3997 ~SplitViewOverviewSessionTest() override = default;
3998
3999 enum class SelectorItemLocation {
4000 CENTER,
4001 ORIGIN,
4002 TOP_RIGHT,
4003 BOTTOM_RIGHT,
4004 BOTTOM_LEFT,
4005 };
4006
SetUp()4007 void SetUp() override {
4008 OverviewSessionTest::SetUp();
4009 EnterTabletMode();
4010 }
4011
split_view_controller()4012 SplitViewController* split_view_controller() {
4013 return SplitViewController::Get(Shell::GetPrimaryRootWindow());
4014 }
4015
IsDividerAnimating()4016 bool IsDividerAnimating() {
4017 return split_view_controller()->IsDividerAnimating();
4018 }
4019
SkipDividerSnapAnimation()4020 void SkipDividerSnapAnimation() {
4021 if (!IsDividerAnimating())
4022 return;
4023 split_view_controller()->StopAndShoveAnimatedDivider();
4024 split_view_controller()->EndResizeImpl();
4025 split_view_controller()->EndTabletSplitViewAfterResizingIfAppropriate();
4026 }
4027
EndSplitView()4028 void EndSplitView() { split_view_controller()->EndSplitView(); }
4029
CheckWindowResizingPerformanceHistograms(const char * trace,int with_empty_overview_grid,int max_latency_with_empty_overview_grid,int with_nonempty_overview_grid,int max_latency_with_nonempty_overview_grid)4030 void CheckWindowResizingPerformanceHistograms(
4031 const char* trace,
4032 int with_empty_overview_grid,
4033 int max_latency_with_empty_overview_grid,
4034 int with_nonempty_overview_grid,
4035 int max_latency_with_nonempty_overview_grid) {
4036 CheckForDuplicateTraceName(trace);
4037 SCOPED_TRACE(trace);
4038
4039 histograms_.ExpectTotalCount(
4040 "Ash.SplitViewResize.PresentationTime.ClamshellMode.SingleWindow",
4041 with_empty_overview_grid);
4042 histograms_.ExpectTotalCount(
4043 "Ash.SplitViewResize.PresentationTime.MaxLatency.ClamshellMode."
4044 "SingleWindow",
4045 max_latency_with_empty_overview_grid);
4046 histograms_.ExpectTotalCount(
4047 "Ash.SplitViewResize.PresentationTime.ClamshellMode.WithOverview",
4048 with_nonempty_overview_grid);
4049 histograms_.ExpectTotalCount(
4050 "Ash.SplitViewResize.PresentationTime.MaxLatency.ClamshellMode."
4051 "WithOverview",
4052 max_latency_with_nonempty_overview_grid);
4053 }
4054
4055 protected:
CreateWindow(const gfx::Rect & bounds)4056 aura::Window* CreateWindow(const gfx::Rect& bounds) {
4057 aura::Window* window = CreateTestWindowInShellWithDelegate(
4058 new SplitViewTestWindowDelegate, -1, bounds);
4059 return window;
4060 }
4061
CreateWindowWithMinimumSize(const gfx::Rect & bounds,const gfx::Size & size)4062 aura::Window* CreateWindowWithMinimumSize(const gfx::Rect& bounds,
4063 const gfx::Size& size) {
4064 SplitViewTestWindowDelegate* delegate = new SplitViewTestWindowDelegate();
4065 aura::Window* window =
4066 CreateTestWindowInShellWithDelegate(delegate, -1, bounds);
4067 delegate->set_minimum_size(size);
4068 return window;
4069 }
4070
GetSplitViewLeftWindowBounds()4071 gfx::Rect GetSplitViewLeftWindowBounds() {
4072 return split_view_controller()->GetSnappedWindowBoundsInScreen(
4073 SplitViewController::LEFT, split_view_controller()->left_window());
4074 }
4075
GetSplitViewRightWindowBounds()4076 gfx::Rect GetSplitViewRightWindowBounds() {
4077 return split_view_controller()->GetSnappedWindowBoundsInScreen(
4078 SplitViewController::RIGHT, split_view_controller()->right_window());
4079 }
4080
GetSplitViewDividerBounds(bool is_dragging)4081 gfx::Rect GetSplitViewDividerBounds(bool is_dragging) {
4082 if (!split_view_controller()->InSplitViewMode())
4083 return gfx::Rect();
4084 return split_view_controller()
4085 ->split_view_divider_->GetDividerBoundsInScreen(is_dragging);
4086 }
4087
GetWorkAreaInScreen(aura::Window * window)4088 gfx::Rect GetWorkAreaInScreen(aura::Window* window) {
4089 return screen_util::GetDisplayWorkAreaBoundsInScreenForActiveDeskContainer(
4090 window);
4091 }
4092
4093 // Drags a overview item |item| from its center or one of its corners
4094 // to |end_location|. This should be used over
4095 // DragWindowTo(OverviewItem*, gfx::Point) when testing snapping a
4096 // window, but the windows centerpoint may be inside a snap region, thus the
4097 // window will not snapped. This function is mostly used to test splitview so
4098 // |long_press| is default to true. Set |long_press| to false if we do not
4099 // want to long press after every press, which enables dragging vertically to
4100 // close an item.
DragWindowTo(OverviewItem * item,const gfx::PointF & end_location,SelectorItemLocation location,bool long_press=true)4101 void DragWindowTo(OverviewItem* item,
4102 const gfx::PointF& end_location,
4103 SelectorItemLocation location,
4104 bool long_press = true) {
4105 gfx::PointF start_location;
4106 switch (location) {
4107 case SelectorItemLocation::CENTER:
4108 start_location = item->target_bounds().CenterPoint();
4109 break;
4110 case SelectorItemLocation::ORIGIN:
4111 start_location = item->target_bounds().origin();
4112 break;
4113 case SelectorItemLocation::TOP_RIGHT:
4114 start_location = item->target_bounds().top_right();
4115 break;
4116 case SelectorItemLocation::BOTTOM_RIGHT:
4117 start_location = item->target_bounds().bottom_right();
4118 break;
4119 case SelectorItemLocation::BOTTOM_LEFT:
4120 start_location = item->target_bounds().bottom_left();
4121 break;
4122 default:
4123 NOTREACHED();
4124 break;
4125 }
4126 overview_session()->InitiateDrag(item, start_location,
4127 /*is_touch_dragging=*/true);
4128 if (long_press)
4129 overview_session()->StartNormalDragMode(start_location);
4130 overview_session()->Drag(item, end_location);
4131 overview_session()->CompleteDrag(item, end_location);
4132 }
4133
4134 // Drags a overview item |item| from its center point to |end_location|.
DragWindowTo(OverviewItem * item,const gfx::PointF & end_location)4135 void DragWindowTo(OverviewItem* item, const gfx::PointF& end_location) {
4136 DragWindowTo(item, end_location, SelectorItemLocation::CENTER, true);
4137 }
4138
4139 private:
4140 class SplitViewTestWindowDelegate : public aura::test::TestWindowDelegate {
4141 public:
4142 SplitViewTestWindowDelegate() = default;
4143 ~SplitViewTestWindowDelegate() override = default;
4144
4145 // aura::test::TestWindowDelegate:
OnWindowDestroying(aura::Window * window)4146 void OnWindowDestroying(aura::Window* window) override { window->Hide(); }
OnWindowDestroyed(aura::Window * window)4147 void OnWindowDestroyed(aura::Window* window) override { delete this; }
4148 };
4149
4150 DISALLOW_COPY_AND_ASSIGN(SplitViewOverviewSessionTest);
4151 };
4152
4153 // Tests that dragging an overview item to the edge of the screen snaps the
4154 // window. If two windows are snapped to left and right side of the screen, exit
4155 // the overview mode.
TEST_P(SplitViewOverviewSessionTest,DragOverviewWindowToSnap)4156 TEST_P(SplitViewOverviewSessionTest, DragOverviewWindowToSnap) {
4157 const gfx::Rect bounds(400, 400);
4158 std::unique_ptr<aura::Window> window1(CreateWindow(bounds));
4159 std::unique_ptr<aura::Window> window2(CreateWindow(bounds));
4160 std::unique_ptr<aura::Window> window3(CreateWindow(bounds));
4161
4162 ToggleOverview();
4163 EXPECT_TRUE(overview_controller()->InOverviewSession());
4164 EXPECT_FALSE(split_view_controller()->InSplitViewMode());
4165
4166 // Drag |window1| selector item to snap to left.
4167 OverviewItem* overview_item1 = GetOverviewItemForWindow(window1.get());
4168 DragWindowTo(overview_item1, gfx::PointF(0, 0));
4169
4170 EXPECT_TRUE(split_view_controller()->InSplitViewMode());
4171 EXPECT_EQ(split_view_controller()->state(),
4172 SplitViewController::State::kLeftSnapped);
4173 EXPECT_EQ(split_view_controller()->left_window(), window1.get());
4174
4175 // Drag |window2| selector item to attempt to snap to left. Since there is
4176 // already one left snapped window |window1|, |window1| will be put in
4177 // overview mode.
4178 OverviewItem* overview_item2 = GetOverviewItemForWindow(window2.get());
4179 DragWindowTo(overview_item2, gfx::PointF(0, 0));
4180
4181 EXPECT_EQ(split_view_controller()->state(),
4182 SplitViewController::State::kLeftSnapped);
4183 EXPECT_EQ(split_view_controller()->left_window(), window2.get());
4184 EXPECT_TRUE(overview_controller()->overview_session()->IsWindowInOverview(
4185 window1.get()));
4186
4187 // Drag |window3| selector item to snap to right.
4188 OverviewItem* overview_item3 = GetOverviewItemForWindow(window3.get());
4189 const gfx::PointF end_location3(GetWorkAreaInScreen(window3.get()).width(),
4190 0.f);
4191 DragWindowTo(overview_item3, end_location3);
4192
4193 EXPECT_EQ(split_view_controller()->state(),
4194 SplitViewController::State::kBothSnapped);
4195 EXPECT_EQ(split_view_controller()->right_window(), window3.get());
4196 EXPECT_FALSE(overview_controller()->InOverviewSession());
4197 }
4198
4199 // Verify the correct behavior when dragging windows in overview mode.
TEST_P(SplitViewOverviewSessionTest,OverviewDragControllerBehavior)4200 TEST_P(SplitViewOverviewSessionTest, OverviewDragControllerBehavior) {
4201 ui::GestureConfiguration* gesture_config =
4202 ui::GestureConfiguration::GetInstance();
4203 gesture_config->set_long_press_time_in_ms(1);
4204 gesture_config->set_show_press_delay_in_ms(1);
4205
4206 std::unique_ptr<aura::Window> window1 = CreateTestWindow();
4207 std::unique_ptr<aura::Window> window2 = CreateTestWindow();
4208
4209 ToggleOverview();
4210 ASSERT_TRUE(overview_controller()->InOverviewSession());
4211
4212 OverviewItem* window_item1 = GetOverviewItemForWindow(window1.get());
4213 OverviewItem* window_item2 = GetOverviewItemForWindow(window2.get());
4214
4215 // Verify that if a drag is orginally horizontal, the drag behavior is drag to
4216 // snap.
4217 using DragBehavior = OverviewWindowDragController::DragBehavior;
4218 ui::test::EventGenerator* generator = GetEventGenerator();
4219 generator->set_current_screen_location(
4220 gfx::ToRoundedPoint(window_item1->target_bounds().CenterPoint()));
4221 generator->PressTouch();
4222
4223 // Simulate a long press, which is required to snap windows.
4224 base::RunLoop run_loop;
4225 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
4226 FROM_HERE, run_loop.QuitClosure(), base::TimeDelta::FromMilliseconds(2));
4227 run_loop.Run();
4228
4229 OverviewWindowDragController* drag_controller =
4230 overview_session()->window_drag_controller();
4231 ASSERT_TRUE(drag_controller);
4232 EXPECT_EQ(DragBehavior::kNormalDrag,
4233 drag_controller->current_drag_behavior());
4234 generator->MoveTouchBy(20, 0);
4235 EXPECT_EQ(DragBehavior::kNormalDrag,
4236 drag_controller->current_drag_behavior());
4237 generator->ReleaseTouch();
4238 EXPECT_EQ(DragBehavior::kNoDrag, drag_controller->current_drag_behavior());
4239
4240 // Verify that if a drag is orginally vertical, the drag behavior is drag to
4241 // close.
4242 generator->set_current_screen_location(
4243 gfx::ToRoundedPoint(window_item2->target_bounds().CenterPoint()));
4244 generator->PressTouch();
4245
4246 // Use small increments otherwise a fling event will be fired.
4247 for (int j = 0; j < 20; ++j)
4248 generator->MoveTouchBy(0, 1);
4249
4250 // A new instance of drag controller gets created each time a drag starts.
4251 drag_controller = overview_session()->window_drag_controller();
4252 EXPECT_EQ(DragBehavior::kDragToClose,
4253 drag_controller->current_drag_behavior());
4254 }
4255
4256 // Verify the window grid size changes as expected when dragging items around in
4257 // overview mode when split view is enabled.
TEST_P(SplitViewOverviewSessionTest,OverviewGridSizeWhileDraggingWithSplitView)4258 TEST_P(SplitViewOverviewSessionTest,
4259 OverviewGridSizeWhileDraggingWithSplitView) {
4260 // Add three windows and enter overview mode.
4261 std::unique_ptr<aura::Window> window1(CreateTestWindow());
4262 std::unique_ptr<aura::Window> window2(CreateTestWindow());
4263 std::unique_ptr<aura::Window> window3(CreateTestWindow());
4264
4265 ToggleOverview();
4266 ASSERT_TRUE(overview_controller()->InOverviewSession());
4267
4268 // Select window one and start the drag.
4269 const int window_width =
4270 Shell::Get()->GetPrimaryRootWindow()->GetBoundsInScreen().width();
4271 OverviewItem* overview_item = GetOverviewItemForWindow(window1.get());
4272 gfx::RectF overview_item_bounds = overview_item->target_bounds();
4273 gfx::PointF start_location(overview_item_bounds.CenterPoint());
4274 overview_session()->InitiateDrag(overview_item, start_location,
4275 /*is_touch_dragging=*/false);
4276
4277 // Verify that when dragged to the left, the window grid is located where the
4278 // right window of split view mode should be.
4279 const gfx::PointF left(0, 0);
4280 overview_session()->Drag(overview_item, left);
4281 EXPECT_FALSE(split_view_controller()->InSplitViewMode());
4282 EXPECT_EQ(SplitViewController::State::kNoSnap,
4283 split_view_controller()->state());
4284 EXPECT_TRUE(split_view_controller()->left_window() == nullptr);
4285 EXPECT_EQ(ShrinkBoundsByHotseatInset(GetSplitViewRightWindowBounds()),
4286 GetGridBounds());
4287
4288 // Verify that when dragged to the right, the window grid is located where the
4289 // left window of split view mode should be.
4290 const gfx::PointF right(window_width, 0);
4291 overview_session()->Drag(overview_item, right);
4292 EXPECT_EQ(SplitViewController::State::kNoSnap,
4293 split_view_controller()->state());
4294 EXPECT_TRUE(split_view_controller()->right_window() == nullptr);
4295 EXPECT_EQ(ShrinkBoundsByHotseatInset(GetSplitViewLeftWindowBounds()),
4296 GetGridBounds());
4297
4298 // Verify that when dragged to the center, the window grid is has the
4299 // dimensions of the work area.
4300 const gfx::PointF center(window_width / 2, 0);
4301 overview_session()->Drag(overview_item, center);
4302 EXPECT_EQ(SplitViewController::State::kNoSnap,
4303 split_view_controller()->state());
4304 EXPECT_EQ(ShrinkBoundsByHotseatInset(GetWorkAreaInScreen(window1.get())),
4305 GetGridBounds());
4306
4307 // Snap window1 to the left and initialize dragging for window2.
4308 overview_session()->Drag(overview_item, left);
4309 overview_session()->CompleteDrag(overview_item, left);
4310 ASSERT_EQ(SplitViewController::State::kLeftSnapped,
4311 split_view_controller()->state());
4312 ASSERT_EQ(window1.get(), split_view_controller()->left_window());
4313 overview_item = GetOverviewItemForWindow(window2.get());
4314 overview_item_bounds = overview_item->target_bounds();
4315 start_location = overview_item_bounds.CenterPoint();
4316 overview_session()->InitiateDrag(overview_item, start_location,
4317 /*is_touch_dragging=*/false);
4318
4319 // Verify that when there is a snapped window, the window grid bounds remain
4320 // constant despite overview items being dragged left and right.
4321 overview_session()->Drag(overview_item, left);
4322 EXPECT_EQ(GetSplitViewRightWindowBounds(), GetGridBounds());
4323 overview_session()->Drag(overview_item, right);
4324 EXPECT_EQ(GetSplitViewRightWindowBounds(), GetGridBounds());
4325 overview_session()->Drag(overview_item, center);
4326 EXPECT_EQ(GetSplitViewRightWindowBounds(), GetGridBounds());
4327 }
4328
4329 // Tests dragging a unsnappable window.
TEST_P(SplitViewOverviewSessionTest,DraggingUnsnappableAppWithSplitView)4330 TEST_P(SplitViewOverviewSessionTest, DraggingUnsnappableAppWithSplitView) {
4331 std::unique_ptr<aura::Window> unsnappable_window = CreateUnsnappableWindow();
4332
4333 // The grid bounds should be the size of the root window minus the shelf.
4334 const gfx::Rect root_window_bounds =
4335 Shell::Get()->GetPrimaryRootWindow()->GetBoundsInScreen();
4336 const gfx::Rect shelf_bounds =
4337 Shelf::ForWindow(Shell::Get()->GetPrimaryRootWindow())->GetIdealBounds();
4338 const gfx::Rect expected_grid_bounds = ShrinkBoundsByHotseatInset(
4339 SubtractRects(root_window_bounds, shelf_bounds));
4340
4341 ToggleOverview();
4342 ASSERT_TRUE(overview_controller()->InOverviewSession());
4343
4344 // Verify that after dragging the unsnappable window to the left and right,
4345 // the window grid bounds do not change.
4346 OverviewItem* overview_item =
4347 GetOverviewItemForWindow(unsnappable_window.get());
4348 overview_session()->InitiateDrag(overview_item,
4349 overview_item->target_bounds().CenterPoint(),
4350 /*is_touch_dragging=*/false);
4351 overview_session()->Drag(overview_item, gfx::PointF());
4352 EXPECT_EQ(expected_grid_bounds, GetGridBounds());
4353 overview_session()->Drag(overview_item,
4354 gfx::PointF(root_window_bounds.right(), 0.f));
4355 EXPECT_EQ(expected_grid_bounds, GetGridBounds());
4356 overview_session()->Drag(overview_item,
4357 gfx::PointF(root_window_bounds.right() / 2.f, 0.f));
4358 EXPECT_EQ(expected_grid_bounds, GetGridBounds());
4359 }
4360
4361 // Test that if an unsnappable window is dragged from overview to where another
4362 // window is already snapped, then there is no snap preview, and if the drag
4363 // ends there, then there is no DCHECK failure (or crash).
TEST_P(SplitViewOverviewSessionTest,DragUnsnappableWindowFromOverviewToSnappedWindow)4364 TEST_P(SplitViewOverviewSessionTest,
4365 DragUnsnappableWindowFromOverviewToSnappedWindow) {
4366 std::unique_ptr<aura::Window> snapped_window = CreateTestWindow();
4367 std::unique_ptr<aura::Window> unsnappable_window = CreateUnsnappableWindow();
4368 ToggleOverview();
4369 split_view_controller()->SnapWindow(snapped_window.get(),
4370 SplitViewController::LEFT);
4371 ASSERT_EQ(1u, overview_session()->grid_list().size());
4372 OverviewGrid* overview_grid = overview_session()->grid_list()[0].get();
4373 OverviewItem* overview_item =
4374 overview_grid->GetOverviewItemContaining(unsnappable_window.get());
4375 overview_session()->InitiateDrag(overview_item,
4376 overview_item->target_bounds().CenterPoint(),
4377 /*is_touch_dragging=*/false);
4378 overview_session()->Drag(overview_item, gfx::PointF());
4379 EXPECT_EQ(SplitViewDragIndicators::WindowDraggingState::kFromOverview,
4380 overview_grid->split_view_drag_indicators()
4381 ->current_window_dragging_state());
4382 overview_session()->CompleteDrag(overview_item, gfx::PointF());
4383 }
4384
TEST_P(SplitViewOverviewSessionTest,Clipping)4385 TEST_P(SplitViewOverviewSessionTest, Clipping) {
4386 // Helper to check if two rectangles have roughly the same aspect ratio. They
4387 // may be off by a bit due to insets but should have roughly the same shape.
4388 auto aspect_ratio_near = [](const gfx::Rect& rect1, const gfx::Rect& rect2) {
4389 DCHECK_GT(rect1.height(), 0);
4390 DCHECK_GT(rect2.height(), 0);
4391 constexpr float kEpsilon = 0.05f;
4392 const float rect1_aspect_ratio =
4393 float{rect1.width()} / float{rect1.height()};
4394 const float rect2_aspect_ratio =
4395 float{rect2.width()} / float{rect2.height()};
4396 return std::abs(rect2_aspect_ratio - rect1_aspect_ratio) < kEpsilon;
4397 };
4398
4399 std::unique_ptr<aura::Window> window1 = CreateTestWindow();
4400 std::unique_ptr<aura::Window> window2 = CreateTestWindow();
4401 std::unique_ptr<aura::Window> window3 = CreateTestWindow(); // Minimized.
4402 std::unique_ptr<aura::Window> window4 = CreateTestWindow(); // Has top inset.
4403 WindowState::Get(window3.get())->Minimize();
4404 window4->SetProperty(aura::client::kTopViewInset, 32);
4405
4406 for (bool portrait : {false, true}) {
4407 SCOPED_TRACE(portrait ? "Portrait" : "Landscape");
4408 if (portrait) {
4409 ScreenOrientationControllerTestApi test_api(
4410 Shell::Get()->screen_orientation_controller());
4411 test_api.SetDisplayRotation(display::Display::ROTATE_90,
4412 display::Display::RotationSource::ACTIVE);
4413 }
4414
4415 const gfx::Rect clipping1 = window1->layer()->clip_rect();
4416 const gfx::Rect clipping2 = window2->layer()->clip_rect();
4417 const gfx::Rect clipping3 = window3->layer()->clip_rect();
4418 const gfx::Rect clipping4 = window4->layer()->clip_rect();
4419 const gfx::Rect maximized_bounds =
4420 screen_util::GetDisplayWorkAreaBoundsInScreenForActiveDeskContainer(
4421 window1.get());
4422 const gfx::Rect split_view_bounds_right =
4423 split_view_controller()->GetSnappedWindowBoundsInScreen(
4424 SplitViewController::SnapPosition::RIGHT,
4425 /*window_for_minimum_size=*/nullptr);
4426
4427 ToggleOverview();
4428
4429 // Tests that after entering overview, windows with no top inset and
4430 // minimized windows still have no clip.
4431 ASSERT_TRUE(overview_controller()->InOverviewSession());
4432 EXPECT_EQ(clipping1, window1->layer()->clip_rect());
4433 EXPECT_EQ(clipping2, window2->layer()->clip_rect());
4434 EXPECT_EQ(clipping3, window3->layer()->clip_rect());
4435 EXPECT_NE(clipping4, window4->layer()->clip_rect());
4436 const gfx::Rect overview_clipping4 = window4->layer()->clip_rect();
4437
4438 OverviewItem* item1 = GetOverviewItemForWindow(window1.get());
4439 OverviewItem* item2 = GetOverviewItemForWindow(window2.get());
4440 OverviewItem* item3 = GetOverviewItemForWindow(window3.get());
4441 OverviewItem* item4 = GetOverviewItemForWindow(window4.get());
4442 overview_session()->InitiateDrag(item1,
4443 item1->target_bounds().CenterPoint(),
4444 /*is_touch_dragging=*/false);
4445
4446 // Tests that after we drag to a preview area, the items target bounds have
4447 // a matching aspect ratio to what the window would have if it were to be
4448 // snapped in splitview. The window clipping should match this, but the
4449 // windows regular bounds remain unchanged (maximized).
4450 overview_session()->Drag(item1, gfx::PointF());
4451 EXPECT_EQ(SplitViewDragIndicators::WindowDraggingState::kToSnapLeft,
4452 overview_session()
4453 ->grid_list()[0]
4454 ->split_view_drag_indicators()
4455 ->current_window_dragging_state());
4456 EXPECT_FALSE(window2->layer()->clip_rect().IsEmpty());
4457 EXPECT_TRUE(aspect_ratio_near(window2->layer()->clip_rect(),
4458 split_view_bounds_right));
4459 EXPECT_TRUE(aspect_ratio_near(
4460 gfx::ToEnclosedRect(item2->GetWindowTargetBoundsWithInsets()),
4461 split_view_bounds_right));
4462 EXPECT_TRUE(
4463 aspect_ratio_near(window2->GetBoundsInScreen(), maximized_bounds));
4464
4465 // The actual window of a minimized window should not be clipped. The
4466 // clipped layer will be the WindowPreviewView of the associated
4467 // OverviewItemView.
4468 EXPECT_TRUE(window3->layer()->clip_rect().IsEmpty());
4469 ui::Layer* preview_layer =
4470 item3->overview_item_view()->preview_view()->layer();
4471 EXPECT_FALSE(preview_layer->clip_rect().IsEmpty());
4472 EXPECT_FALSE(preview_layer->transform().IsIdentity());
4473 // The clip rect is affected by |preview_layer|'s transform so apply it.
4474 gfx::RectF clip_rect3_f(preview_layer->clip_rect());
4475 preview_layer->transform().TransformRect(&clip_rect3_f);
4476 const gfx::Rect clip_rects3 = gfx::ToEnclosedRect(clip_rect3_f);
4477 EXPECT_TRUE(aspect_ratio_near(clip_rects3, split_view_bounds_right));
4478 EXPECT_TRUE(aspect_ratio_near(
4479 gfx::ToEnclosedRect(item3->GetWindowTargetBoundsWithInsets()),
4480 split_view_bounds_right));
4481 EXPECT_TRUE(
4482 aspect_ratio_near(window3->GetBoundsInScreen(), maximized_bounds));
4483
4484 // A window with top view inset should be clipped, but with a new clipping
4485 // than the original overview clipping.
4486 EXPECT_FALSE(window4->layer()->clip_rect().IsEmpty());
4487 EXPECT_NE(overview_clipping4, window4->layer()->clip_rect());
4488 EXPECT_TRUE(aspect_ratio_near(window4->layer()->clip_rect(),
4489 split_view_bounds_right));
4490 EXPECT_TRUE(aspect_ratio_near(
4491 gfx::ToEnclosedRect(item4->GetWindowTargetBoundsWithInsets()),
4492 split_view_bounds_right));
4493 EXPECT_TRUE(
4494 aspect_ratio_near(window4->GetBoundsInScreen(), maximized_bounds));
4495
4496 // Tests that after snapping, the aspect ratios should be the same as being
4497 // in the preview area.
4498 overview_session()->CompleteDrag(item1, gfx::PointF());
4499 ASSERT_EQ(SplitViewController::State::kLeftSnapped,
4500 split_view_controller()->state());
4501 EXPECT_FALSE(window2->layer()->clip_rect().IsEmpty());
4502 EXPECT_TRUE(aspect_ratio_near(window2->layer()->clip_rect(),
4503 split_view_bounds_right));
4504 EXPECT_TRUE(aspect_ratio_near(
4505 gfx::ToEnclosedRect(item2->GetWindowTargetBoundsWithInsets()),
4506 split_view_bounds_right));
4507 EXPECT_TRUE(
4508 aspect_ratio_near(window2->GetBoundsInScreen(), maximized_bounds));
4509
4510 EXPECT_TRUE(window3->layer()->clip_rect().IsEmpty());
4511 EXPECT_TRUE(aspect_ratio_near(clip_rects3, split_view_bounds_right));
4512 EXPECT_TRUE(aspect_ratio_near(
4513 gfx::ToEnclosedRect(item3->GetWindowTargetBoundsWithInsets()),
4514 split_view_bounds_right));
4515 EXPECT_TRUE(
4516 aspect_ratio_near(window3->GetBoundsInScreen(), maximized_bounds));
4517
4518 EXPECT_FALSE(window4->layer()->clip_rect().IsEmpty());
4519 EXPECT_NE(overview_clipping4, window4->layer()->clip_rect());
4520 EXPECT_TRUE(aspect_ratio_near(window4->layer()->clip_rect(),
4521 split_view_bounds_right));
4522 EXPECT_TRUE(aspect_ratio_near(
4523 gfx::ToEnclosedRect(item4->GetWindowTargetBoundsWithInsets()),
4524 split_view_bounds_right));
4525 EXPECT_TRUE(
4526 aspect_ratio_near(window4->GetBoundsInScreen(), maximized_bounds));
4527
4528 // Tests that the clipping is reset after exiting overview.
4529 EndSplitView();
4530 ToggleOverview();
4531 EXPECT_EQ(clipping1, window1->layer()->clip_rect());
4532 EXPECT_EQ(clipping2, window2->layer()->clip_rect());
4533 EXPECT_EQ(clipping3, window3->layer()->clip_rect());
4534 EXPECT_EQ(clipping4, window4->layer()->clip_rect());
4535 }
4536 }
4537
4538 // Tests that when splitview is inactive, there is no need for aspect ratio
4539 // changes, so there is no clipping on the overview windows. Regression test for
4540 // crbug.com/1020440.
TEST_P(SplitViewOverviewSessionTest,NoClippingWhenSplitviewDisabled)4541 TEST_P(SplitViewOverviewSessionTest, NoClippingWhenSplitviewDisabled) {
4542 std::unique_ptr<aura::Window> window1 = CreateTestWindow();
4543 std::unique_ptr<aura::Window> window2 = CreateTestWindow();
4544
4545 // Splitview is disabled when chromeVox is enabled.
4546 Shell::Get()->accessibility_controller()->SetSpokenFeedbackEnabled(
4547 true, A11Y_NOTIFICATION_NONE);
4548 ASSERT_FALSE(ShouldAllowSplitView());
4549 const gfx::Rect clipping1 = window1->layer()->clip_rect();
4550 const gfx::Rect clipping2 = window2->layer()->clip_rect();
4551
4552 ToggleOverview();
4553 ASSERT_TRUE(overview_controller()->InOverviewSession());
4554 EXPECT_EQ(clipping1, window1->layer()->clip_rect());
4555 EXPECT_EQ(clipping2, window2->layer()->clip_rect());
4556
4557 // Drag to the edge of the screen. There should be no clipping and no crash.
4558 OverviewItem* item1 = GetOverviewItemForWindow(window1.get());
4559 overview_session()->InitiateDrag(item1, item1->target_bounds().CenterPoint(),
4560 /*is_touch_dragging=*/false);
4561 overview_session()->Drag(item1, gfx::PointF());
4562 EXPECT_EQ(clipping1, window1->layer()->clip_rect());
4563 EXPECT_EQ(clipping2, window2->layer()->clip_rect());
4564 }
4565
4566 // Tests that if there is only one window in the MRU window list in the overview
4567 // mode, snapping the window to one side of the screen will not end the overview
4568 // mode even if there is no more window left in the overview window grid.
TEST_P(SplitViewOverviewSessionTest,EmptyWindowsListNotExitOverview)4569 TEST_P(SplitViewOverviewSessionTest, EmptyWindowsListNotExitOverview) {
4570 const gfx::Rect bounds(400, 400);
4571 std::unique_ptr<aura::Window> window1(CreateWindow(bounds));
4572
4573 ToggleOverview();
4574 EXPECT_TRUE(overview_controller()->InOverviewSession());
4575
4576 // Drag |window1| selector item to snap to left.
4577 OverviewItem* overview_item1 = GetOverviewItemForWindow(window1.get());
4578 DragWindowTo(overview_item1, gfx::PointF());
4579
4580 // Test that overview mode is active in this single window case.
4581 EXPECT_TRUE(split_view_controller()->InSplitViewMode());
4582 EXPECT_EQ(split_view_controller()->state(),
4583 SplitViewController::State::kLeftSnapped);
4584 EXPECT_TRUE(overview_controller()->InOverviewSession());
4585
4586 // Create a new window should exit the overview mode.
4587 std::unique_ptr<aura::Window> window2(CreateWindow(bounds));
4588 wm::ActivateWindow(window2.get());
4589 EXPECT_FALSE(overview_controller()->InOverviewSession());
4590 EXPECT_EQ(split_view_controller()->state(),
4591 SplitViewController::State::kBothSnapped);
4592 // If there are only 2 snapped windows, close one of them should enter
4593 // overview mode.
4594 window2.reset();
4595 EXPECT_TRUE(overview_controller()->InOverviewSession());
4596
4597 // If there are more than 2 windows in overview
4598 std::unique_ptr<aura::Window> window3(CreateWindow(bounds));
4599 std::unique_ptr<aura::Window> window4(CreateWindow(bounds));
4600 wm::ActivateWindow(window3.get());
4601 wm::ActivateWindow(window4.get());
4602 EXPECT_FALSE(overview_controller()->InOverviewSession());
4603 EXPECT_EQ(split_view_controller()->state(),
4604 SplitViewController::State::kBothSnapped);
4605 ToggleOverview();
4606 EXPECT_TRUE(overview_controller()->InOverviewSession());
4607 window3.reset();
4608 EXPECT_TRUE(overview_controller()->InOverviewSession());
4609 window4.reset();
4610 EXPECT_TRUE(overview_controller()->InOverviewSession());
4611
4612 // Test that if there is only 1 snapped window, and no window in the overview
4613 // grid, ToggleOverview() can't end overview.
4614 ToggleOverview();
4615 EXPECT_TRUE(overview_controller()->InOverviewSession());
4616
4617 EndSplitView();
4618 EXPECT_FALSE(split_view_controller()->InSplitViewMode());
4619 EXPECT_TRUE(overview_controller()->InOverviewSession());
4620
4621 // Test that ToggleOverview() can end overview if we're not in split view
4622 // mode.
4623 ToggleOverview();
4624 EXPECT_FALSE(overview_controller()->InOverviewSession());
4625
4626 // Now enter overview and split view again. Test that exiting tablet mode can
4627 // end split view and overview correctly.
4628 ToggleOverview();
4629 overview_item1 = GetOverviewItemForWindow(window1.get());
4630 DragWindowTo(overview_item1, gfx::PointF());
4631 EXPECT_TRUE(split_view_controller()->InSplitViewMode());
4632 EXPECT_TRUE(overview_controller()->InOverviewSession());
4633 Shell::Get()->tablet_mode_controller()->SetEnabledForTest(false);
4634 EXPECT_FALSE(split_view_controller()->InSplitViewMode());
4635 EXPECT_FALSE(overview_controller()->InOverviewSession());
4636
4637 // Test that closing all windows in overview can end overview if we're not in
4638 // split view mode.
4639 ToggleOverview();
4640 EXPECT_TRUE(overview_controller()->InOverviewSession());
4641 window1.reset();
4642 EXPECT_FALSE(overview_controller()->InOverviewSession());
4643 }
4644
4645 // Tests using Alt+[ on a maximized window.
TEST_P(SplitViewOverviewSessionTest,AltLeftSquareBracketOnMaximizedWindow)4646 TEST_P(SplitViewOverviewSessionTest, AltLeftSquareBracketOnMaximizedWindow) {
4647 std::unique_ptr<aura::Window> snapped_window = CreateTestWindow();
4648 std::unique_ptr<aura::Window> overview_window = CreateTestWindow();
4649 wm::ActivateWindow(snapped_window.get());
4650 WindowState* snapped_window_state = WindowState::Get(snapped_window.get());
4651 EXPECT_EQ(WindowStateType::kMaximized, snapped_window_state->GetStateType());
4652 EXPECT_EQ(SplitViewController::State::kNoSnap,
4653 split_view_controller()->state());
4654 EXPECT_FALSE(InOverviewSession());
4655 const WMEvent alt_left_square_bracket(WM_EVENT_CYCLE_SNAP_LEFT);
4656 snapped_window_state->OnWMEvent(&alt_left_square_bracket);
4657 EXPECT_TRUE(wm::IsActiveWindow(snapped_window.get()));
4658 EXPECT_EQ(WindowStateType::kLeftSnapped,
4659 snapped_window_state->GetStateType());
4660 EXPECT_EQ(SplitViewController::State::kLeftSnapped,
4661 split_view_controller()->state());
4662 EXPECT_EQ(snapped_window.get(), split_view_controller()->left_window());
4663 EXPECT_TRUE(InOverviewSession());
4664 }
4665
4666 // Tests using Alt+] on a maximized window.
TEST_P(SplitViewOverviewSessionTest,AltRightSquareBracketOnMaximizedWindow)4667 TEST_P(SplitViewOverviewSessionTest, AltRightSquareBracketOnMaximizedWindow) {
4668 std::unique_ptr<aura::Window> snapped_window = CreateTestWindow();
4669 std::unique_ptr<aura::Window> overview_window = CreateTestWindow();
4670 wm::ActivateWindow(snapped_window.get());
4671 WindowState* snapped_window_state = WindowState::Get(snapped_window.get());
4672 EXPECT_EQ(WindowStateType::kMaximized, snapped_window_state->GetStateType());
4673 EXPECT_EQ(SplitViewController::State::kNoSnap,
4674 split_view_controller()->state());
4675 EXPECT_FALSE(InOverviewSession());
4676 const WMEvent alt_right_square_bracket(WM_EVENT_CYCLE_SNAP_RIGHT);
4677 snapped_window_state->OnWMEvent(&alt_right_square_bracket);
4678 EXPECT_TRUE(wm::IsActiveWindow(snapped_window.get()));
4679 EXPECT_EQ(WindowStateType::kRightSnapped,
4680 snapped_window_state->GetStateType());
4681 EXPECT_EQ(SplitViewController::State::kRightSnapped,
4682 split_view_controller()->state());
4683 EXPECT_EQ(snapped_window.get(), split_view_controller()->right_window());
4684 EXPECT_TRUE(InOverviewSession());
4685 }
4686
4687 // Tests using Alt+[ and Alt+] on an unsnappable window.
TEST_P(SplitViewOverviewSessionTest,AltSquareBracketOnUnsnappableWindow)4688 TEST_P(SplitViewOverviewSessionTest, AltSquareBracketOnUnsnappableWindow) {
4689 std::unique_ptr<aura::Window> unsnappable_window = CreateUnsnappableWindow();
4690 std::unique_ptr<aura::Window> other_window = CreateTestWindow();
4691 wm::ActivateWindow(unsnappable_window.get());
4692 WindowState* unsnappable_window_state =
4693 WindowState::Get(unsnappable_window.get());
4694 const auto expect_unsnappable_window_is_active_and_maximized =
4695 [this, &unsnappable_window, unsnappable_window_state]() {
4696 EXPECT_TRUE(wm::IsActiveWindow(unsnappable_window.get()));
4697 EXPECT_EQ(WindowStateType::kMaximized,
4698 unsnappable_window_state->GetStateType());
4699 EXPECT_FALSE(split_view_controller()->InSplitViewMode());
4700 EXPECT_FALSE(InOverviewSession());
4701 };
4702 expect_unsnappable_window_is_active_and_maximized();
4703 const WMEvent alt_left_square_bracket(WM_EVENT_CYCLE_SNAP_LEFT);
4704 unsnappable_window_state->OnWMEvent(&alt_left_square_bracket);
4705 expect_unsnappable_window_is_active_and_maximized();
4706 const WMEvent alt_right_square_bracket(WM_EVENT_CYCLE_SNAP_RIGHT);
4707 unsnappable_window_state->OnWMEvent(&alt_right_square_bracket);
4708 expect_unsnappable_window_is_active_and_maximized();
4709 }
4710
4711 // Tests using Alt+[ on a left snapped window, and Alt+] on a right snapped
4712 // window.
TEST_P(SplitViewOverviewSessionTest,AltSquareBracketOnSameSideSnappedWindow)4713 TEST_P(SplitViewOverviewSessionTest, AltSquareBracketOnSameSideSnappedWindow) {
4714 std::unique_ptr<aura::Window> window1 = CreateTestWindow();
4715 std::unique_ptr<aura::Window> window2 = CreateTestWindow();
4716 const auto test_unsnapping_window1 = [this,
4717 &window1](WMEventType event_type) {
4718 wm::ActivateWindow(window1.get());
4719 WindowState* window1_state = WindowState::Get(window1.get());
4720 const WMEvent event(event_type);
4721 window1_state->OnWMEvent(&event);
4722 EXPECT_TRUE(wm::IsActiveWindow(window1.get()));
4723 EXPECT_EQ(WindowStateType::kMaximized, window1_state->GetStateType());
4724 EXPECT_FALSE(split_view_controller()->InSplitViewMode());
4725 EXPECT_FALSE(InOverviewSession());
4726 };
4727 // Test Alt+[ with active window snapped on left and overview on right.
4728 ToggleOverview();
4729 split_view_controller()->SnapWindow(window1.get(), SplitViewController::LEFT);
4730 test_unsnapping_window1(WM_EVENT_CYCLE_SNAP_LEFT);
4731 // Test Alt+] with active window snapped on right and overview on left.
4732 ToggleOverview();
4733 split_view_controller()->SnapWindow(window1.get(),
4734 SplitViewController::RIGHT);
4735 test_unsnapping_window1(WM_EVENT_CYCLE_SNAP_RIGHT);
4736 // Test Alt+[ with active window snapped on left and other window snapped on
4737 // right, if the left window is the default snapped window.
4738 split_view_controller()->SnapWindow(window1.get(), SplitViewController::LEFT);
4739 split_view_controller()->SnapWindow(window2.get(),
4740 SplitViewController::RIGHT);
4741 test_unsnapping_window1(WM_EVENT_CYCLE_SNAP_LEFT);
4742 // Test Alt+[ with active window snapped on left and other window snapped on
4743 // right, if the right window is the default snapped window.
4744 split_view_controller()->SnapWindow(window2.get(),
4745 SplitViewController::RIGHT);
4746 split_view_controller()->SnapWindow(window1.get(), SplitViewController::LEFT);
4747 test_unsnapping_window1(WM_EVENT_CYCLE_SNAP_LEFT);
4748 // Test Alt+] with active window snapped on right and other window snapped on
4749 // left, if the left window is the default snapped window.
4750 split_view_controller()->SnapWindow(window2.get(), SplitViewController::LEFT);
4751 split_view_controller()->SnapWindow(window1.get(),
4752 SplitViewController::RIGHT);
4753 test_unsnapping_window1(WM_EVENT_CYCLE_SNAP_RIGHT);
4754 // Test Alt+] with active window snapped on right and other window snapped on
4755 // left, if the right window is the default snapped window.
4756 split_view_controller()->SnapWindow(window1.get(),
4757 SplitViewController::RIGHT);
4758 split_view_controller()->SnapWindow(window2.get(), SplitViewController::LEFT);
4759 test_unsnapping_window1(WM_EVENT_CYCLE_SNAP_RIGHT);
4760 }
4761
4762 // Tests using Alt+[ on a right snapped window, and Alt+] on a left snapped
4763 // window.
TEST_P(SplitViewOverviewSessionTest,AltSquareBracketOnOppositeSideSnappedWindow)4764 TEST_P(SplitViewOverviewSessionTest,
4765 AltSquareBracketOnOppositeSideSnappedWindow) {
4766 std::unique_ptr<aura::Window> window1 = CreateTestWindow();
4767 std::unique_ptr<aura::Window> window2 = CreateTestWindow();
4768 const auto test_left_snapping_window1 = [this, &window1, &window2]() {
4769 wm::ActivateWindow(window1.get());
4770 WindowState* window1_state = WindowState::Get(window1.get());
4771 const WMEvent alt_left_square_bracket(WM_EVENT_CYCLE_SNAP_LEFT);
4772 window1_state->OnWMEvent(&alt_left_square_bracket);
4773 EXPECT_TRUE(wm::IsActiveWindow(window1.get()));
4774 EXPECT_EQ(WindowStateType::kLeftSnapped, window1_state->GetStateType());
4775 EXPECT_EQ(SplitViewController::State::kLeftSnapped,
4776 split_view_controller()->state());
4777 EXPECT_EQ(window1.get(), split_view_controller()->left_window());
4778 ASSERT_TRUE(InOverviewSession());
4779 EXPECT_TRUE(GetOverviewItemForWindow(window2.get()));
4780 };
4781 const auto test_right_snapping_window1 = [this, &window1, &window2]() {
4782 wm::ActivateWindow(window1.get());
4783 WindowState* window1_state = WindowState::Get(window1.get());
4784 const WMEvent alt_right_square_bracket(WM_EVENT_CYCLE_SNAP_RIGHT);
4785 window1_state->OnWMEvent(&alt_right_square_bracket);
4786 EXPECT_TRUE(wm::IsActiveWindow(window1.get()));
4787 EXPECT_EQ(WindowStateType::kRightSnapped, window1_state->GetStateType());
4788 EXPECT_EQ(SplitViewController::State::kRightSnapped,
4789 split_view_controller()->state());
4790 EXPECT_EQ(window1.get(), split_view_controller()->right_window());
4791 ASSERT_TRUE(InOverviewSession());
4792 EXPECT_TRUE(GetOverviewItemForWindow(window2.get()));
4793 };
4794 // Test Alt+[ with active window snapped on right and overview on left.
4795 ToggleOverview();
4796 split_view_controller()->SnapWindow(window1.get(),
4797 SplitViewController::RIGHT);
4798 test_left_snapping_window1();
4799 // Test Alt+] with active window snapped on left and overview on right.
4800 test_right_snapping_window1();
4801 // Test Alt+[ with active window snapped on right and other window snapped on
4802 // left, if the right window is the default snapped window.
4803 split_view_controller()->SnapWindow(window2.get(), SplitViewController::LEFT);
4804 test_left_snapping_window1();
4805 // Test Alt+] with active window snapped on left and other window snapped on
4806 // right, if the left window is the default snapped window.
4807 split_view_controller()->SnapWindow(window2.get(),
4808 SplitViewController::RIGHT);
4809 test_right_snapping_window1();
4810 // Test Alt+[ with active window snapped on right and other window snapped on
4811 // left, if the left window is the default snapped window.
4812 EndSplitView();
4813 split_view_controller()->SnapWindow(window2.get(), SplitViewController::LEFT);
4814 split_view_controller()->SnapWindow(window1.get(),
4815 SplitViewController::RIGHT);
4816 test_left_snapping_window1();
4817 // Test Alt+] with active window snapped on left and other window snapped on
4818 // right, if the right window is the default snapped window.
4819 EndSplitView();
4820 split_view_controller()->SnapWindow(window2.get(),
4821 SplitViewController::RIGHT);
4822 split_view_controller()->SnapWindow(window1.get(), SplitViewController::LEFT);
4823 test_right_snapping_window1();
4824 }
4825
4826 // Test the overview window drag functionalities when screen rotates.
TEST_P(SplitViewOverviewSessionTest,SplitViewRotationTest)4827 TEST_P(SplitViewOverviewSessionTest, SplitViewRotationTest) {
4828 UpdateDisplay("807x407");
4829 int64_t display_id = display::Screen::GetScreen()->GetPrimaryDisplay().id();
4830 display::DisplayManager* display_manager = Shell::Get()->display_manager();
4831 display::test::ScopedSetInternalDisplayId set_internal(display_manager,
4832 display_id);
4833 ScreenOrientationControllerTestApi test_api(
4834 Shell::Get()->screen_orientation_controller());
4835
4836 // Set the screen orientation to LANDSCAPE_PRIMARY.
4837 test_api.SetDisplayRotation(display::Display::ROTATE_0,
4838 display::Display::RotationSource::ACTIVE);
4839 EXPECT_EQ(test_api.GetCurrentOrientation(),
4840 OrientationLockType::kLandscapePrimary);
4841
4842 const gfx::Rect bounds(400, 400);
4843 std::unique_ptr<aura::Window> window1(CreateWindow(bounds));
4844 std::unique_ptr<aura::Window> window2(CreateWindow(bounds));
4845
4846 ToggleOverview();
4847 // Test that dragging |window1| to the left of the screen snaps it to left.
4848 OverviewItem* overview_item1 = GetOverviewItemForWindow(window1.get());
4849 DragWindowTo(overview_item1, gfx::PointF());
4850 EXPECT_EQ(split_view_controller()->state(),
4851 SplitViewController::State::kLeftSnapped);
4852 EXPECT_EQ(split_view_controller()->left_window(), window1.get());
4853
4854 // Test that dragging |window2| to the right of the screen snaps it to right.
4855 OverviewItem* overview_item2 = GetOverviewItemForWindow(window2.get());
4856 gfx::Rect work_area_rect = GetWorkAreaInScreen(window2.get());
4857 gfx::PointF end_location2(work_area_rect.width(), work_area_rect.height());
4858 DragWindowTo(overview_item2, end_location2);
4859 EXPECT_EQ(split_view_controller()->state(),
4860 SplitViewController::State::kBothSnapped);
4861 EXPECT_EQ(split_view_controller()->right_window(), window2.get());
4862
4863 // Test that |left_window_| was snapped to left after rotated 0 degree.
4864 gfx::Rect left_window_bounds =
4865 split_view_controller()->left_window()->GetBoundsInScreen();
4866 EXPECT_EQ(left_window_bounds.x(), work_area_rect.x());
4867 EXPECT_EQ(left_window_bounds.y(), work_area_rect.y());
4868 EndSplitView();
4869
4870 // Rotate the screen by 270 degree.
4871 test_api.SetDisplayRotation(display::Display::ROTATE_270,
4872 display::Display::RotationSource::ACTIVE);
4873 EXPECT_EQ(test_api.GetCurrentOrientation(),
4874 OrientationLockType::kPortraitPrimary);
4875 ToggleOverview();
4876
4877 // Test that dragging |window1| to the top of the screen snaps it to left.
4878 overview_item1 = GetOverviewItemForWindow(window1.get());
4879 DragWindowTo(overview_item1, gfx::PointF(0, 0));
4880 EXPECT_EQ(split_view_controller()->state(),
4881 SplitViewController::State::kLeftSnapped);
4882 EXPECT_EQ(split_view_controller()->left_window(), window1.get());
4883
4884 // Test that dragging |window2| to the bottom of the screen snaps it to right.
4885 overview_item2 = GetOverviewItemForWindow(window2.get());
4886 work_area_rect = GetWorkAreaInScreen(window2.get());
4887 end_location2 = gfx::PointF(work_area_rect.width(), work_area_rect.height());
4888 DragWindowTo(overview_item2, end_location2, SelectorItemLocation::ORIGIN);
4889 EXPECT_EQ(split_view_controller()->state(),
4890 SplitViewController::State::kBothSnapped);
4891 EXPECT_EQ(split_view_controller()->right_window(), window2.get());
4892
4893 // Test that |left_window_| was snapped to top after rotated 270 degree.
4894 left_window_bounds =
4895 split_view_controller()->left_window()->GetBoundsInScreen();
4896 EXPECT_EQ(left_window_bounds.x(), work_area_rect.x());
4897 EXPECT_EQ(left_window_bounds.y(), work_area_rect.y());
4898 EndSplitView();
4899
4900 // Rotate the screen by 180 degree.
4901 test_api.SetDisplayRotation(display::Display::ROTATE_180,
4902 display::Display::RotationSource::ACTIVE);
4903 EXPECT_EQ(test_api.GetCurrentOrientation(),
4904 OrientationLockType::kLandscapeSecondary);
4905 ToggleOverview();
4906
4907 // Test that dragging |window1| to the left of the screen snaps it to right.
4908 overview_item1 = GetOverviewItemForWindow(window1.get());
4909 DragWindowTo(overview_item1, gfx::PointF());
4910 EXPECT_EQ(split_view_controller()->state(),
4911 SplitViewController::State::kRightSnapped);
4912 EXPECT_EQ(split_view_controller()->right_window(), window1.get());
4913
4914 // Test that dragging |window2| to the right of the screen snaps it to left.
4915 overview_item2 = GetOverviewItemForWindow(window2.get());
4916 work_area_rect = GetWorkAreaInScreen(window2.get());
4917 end_location2 = gfx::PointF(work_area_rect.width(), work_area_rect.height());
4918 DragWindowTo(overview_item2, end_location2, SelectorItemLocation::ORIGIN);
4919 EXPECT_EQ(split_view_controller()->state(),
4920 SplitViewController::State::kBothSnapped);
4921 EXPECT_EQ(split_view_controller()->left_window(), window2.get());
4922
4923 // Test that |right_window_| was snapped to left after rotated 180 degree.
4924 gfx::Rect right_window_bounds =
4925 split_view_controller()->right_window()->GetBoundsInScreen();
4926 EXPECT_EQ(right_window_bounds.x(), work_area_rect.x());
4927 EXPECT_EQ(right_window_bounds.y(), work_area_rect.y());
4928 EndSplitView();
4929
4930 // Rotate the screen by 90 degree.
4931 test_api.SetDisplayRotation(display::Display::ROTATE_90,
4932 display::Display::RotationSource::ACTIVE);
4933 EXPECT_EQ(test_api.GetCurrentOrientation(),
4934 OrientationLockType::kPortraitSecondary);
4935 ToggleOverview();
4936
4937 // Test that dragging |window1| to the top of the screen snaps it to right.
4938 overview_item1 = GetOverviewItemForWindow(window1.get());
4939 DragWindowTo(overview_item1, gfx::PointF(0, 0));
4940 EXPECT_EQ(split_view_controller()->state(),
4941 SplitViewController::State::kRightSnapped);
4942 EXPECT_EQ(split_view_controller()->right_window(), window1.get());
4943
4944 // Test that dragging |window2| to the bottom of the screen snaps it to left.
4945 overview_item2 = GetOverviewItemForWindow(window2.get());
4946 work_area_rect = GetWorkAreaInScreen(window2.get());
4947 end_location2 = gfx::PointF(work_area_rect.width(), work_area_rect.height());
4948 DragWindowTo(overview_item2, end_location2);
4949 EXPECT_EQ(split_view_controller()->state(),
4950 SplitViewController::State::kBothSnapped);
4951 EXPECT_EQ(split_view_controller()->left_window(), window2.get());
4952
4953 // Test that |right_window_| was snapped to top after rotated 90 degree.
4954 right_window_bounds =
4955 split_view_controller()->right_window()->GetBoundsInScreen();
4956 EXPECT_EQ(right_window_bounds.x(), work_area_rect.x());
4957 EXPECT_EQ(right_window_bounds.y(), work_area_rect.y());
4958 EndSplitView();
4959 }
4960
4961 // Test that when split view mode and overview mode are both active at the same
4962 // time, dragging the split view divider resizes the bounds of snapped window
4963 // and the bounds of overview window grids at the same time.
TEST_P(SplitViewOverviewSessionTest,SplitViewOverviewBothActiveTest)4964 TEST_P(SplitViewOverviewSessionTest, SplitViewOverviewBothActiveTest) {
4965 UpdateDisplay("907x407");
4966
4967 const gfx::Rect bounds(400, 400);
4968 std::unique_ptr<aura::Window> window1(CreateWindow(bounds));
4969 std::unique_ptr<aura::Window> window2(CreateWindow(bounds));
4970 std::unique_ptr<aura::Window> window3(CreateWindow(bounds));
4971
4972 ToggleOverview();
4973
4974 // Drag |window1| selector item to snap to left.
4975 OverviewItem* overview_item1 = GetOverviewItemForWindow(window1.get());
4976 DragWindowTo(overview_item1, gfx::PointF());
4977
4978 EXPECT_EQ(split_view_controller()->state(),
4979 SplitViewController::State::kLeftSnapped);
4980 const gfx::Rect window1_bounds = window1->GetBoundsInScreen();
4981 const gfx::Rect overview_grid_bounds = GetGridBounds();
4982 const gfx::Rect divider_bounds =
4983 GetSplitViewDividerBounds(false /* is_dragging */);
4984
4985 // Test that window1, divider, overview grid are aligned horizontally.
4986 EXPECT_EQ(window1_bounds.right(), divider_bounds.x());
4987 EXPECT_EQ(divider_bounds.right(), overview_grid_bounds.x());
4988
4989 const gfx::Point resize_start_location(divider_bounds.CenterPoint());
4990 split_view_controller()->StartResize(resize_start_location);
4991 const gfx::Point resize_end_location(300, 0);
4992 split_view_controller()->EndResize(resize_end_location);
4993 SkipDividerSnapAnimation();
4994
4995 const gfx::Rect window1_bounds_after_resize = window1->GetBoundsInScreen();
4996 const gfx::Rect overview_grid_bounds_after_resize = GetGridBounds();
4997 const gfx::Rect divider_bounds_after_resize =
4998 GetSplitViewDividerBounds(false /* is_dragging */);
4999
5000 // Test that window1, divider, overview grid are still aligned horizontally
5001 // after resizing.
5002 EXPECT_EQ(window1_bounds.right(), divider_bounds.x());
5003 EXPECT_EQ(divider_bounds.right(), overview_grid_bounds.x());
5004
5005 // Test that window1, divider, overview grid's bounds are changed after
5006 // resizing.
5007 EXPECT_NE(window1_bounds, window1_bounds_after_resize);
5008 EXPECT_NE(overview_grid_bounds, overview_grid_bounds_after_resize);
5009 EXPECT_NE(divider_bounds, divider_bounds_after_resize);
5010 }
5011
5012 // Verify that selecting an unsnappable window while in split view works as
5013 // intended.
TEST_P(SplitViewOverviewSessionTest,SelectUnsnappableWindowInSplitView)5014 TEST_P(SplitViewOverviewSessionTest, SelectUnsnappableWindowInSplitView) {
5015 // Create one snappable and one unsnappable window.
5016 std::unique_ptr<aura::Window> window = CreateTestWindow();
5017 std::unique_ptr<aura::Window> unsnappable_window = CreateUnsnappableWindow();
5018
5019 ToggleOverview();
5020 ASSERT_TRUE(overview_controller()->InOverviewSession());
5021
5022 // Snap the snappable window to enter split view mode.
5023 split_view_controller()->SnapWindow(window.get(), SplitViewController::LEFT);
5024 ASSERT_TRUE(split_view_controller()->InSplitViewMode());
5025
5026 // Select the unsnappable window.
5027 OverviewItem* overview_item =
5028 GetOverviewItemForWindow(unsnappable_window.get());
5029 ui::test::EventGenerator* generator = GetEventGenerator();
5030 generator->set_current_screen_location(
5031 gfx::ToRoundedPoint(overview_item->target_bounds().CenterPoint()));
5032 generator->ClickLeftButton();
5033
5034 // Verify that we are out of split view and overview mode, and that the active
5035 // window is the unsnappable window.
5036 EXPECT_FALSE(split_view_controller()->InSplitViewMode());
5037 EXPECT_FALSE(overview_controller()->InOverviewSession());
5038 EXPECT_EQ(unsnappable_window.get(), window_util::GetActiveWindow());
5039
5040 std::unique_ptr<aura::Window> window2 = CreateTestWindow();
5041 ToggleOverview();
5042 split_view_controller()->SnapWindow(window.get(), SplitViewController::LEFT);
5043 split_view_controller()->SnapWindow(window2.get(),
5044 SplitViewController::RIGHT);
5045
5046 // Split view mode should be active. Overview mode should be ended.
5047 EXPECT_TRUE(split_view_controller()->InSplitViewMode());
5048 EXPECT_EQ(SplitViewController::State::kBothSnapped,
5049 split_view_controller()->state());
5050 EXPECT_FALSE(overview_controller()->InOverviewSession());
5051
5052 ToggleOverview();
5053 EXPECT_TRUE(split_view_controller()->InSplitViewMode());
5054 EXPECT_EQ(SplitViewController::State::kLeftSnapped,
5055 split_view_controller()->state());
5056 EXPECT_TRUE(overview_controller()->InOverviewSession());
5057
5058 // Now select the unsnappable window.
5059 overview_item = GetOverviewItemForWindow(unsnappable_window.get());
5060 generator->set_current_screen_location(
5061 gfx::ToRoundedPoint(overview_item->target_bounds().CenterPoint()));
5062 generator->ClickLeftButton();
5063
5064 // Split view mode should be ended. And the unsnappable window should be the
5065 // active window now.
5066 EXPECT_FALSE(split_view_controller()->InSplitViewMode());
5067 EXPECT_FALSE(overview_controller()->InOverviewSession());
5068 EXPECT_EQ(unsnappable_window.get(), window_util::GetActiveWindow());
5069 }
5070
5071 // Verify that when in overview mode, the selector items unsnappable indicator
5072 // shows up when expected.
TEST_P(SplitViewOverviewSessionTest,OverviewUnsnappableIndicatorVisibility)5073 TEST_P(SplitViewOverviewSessionTest, OverviewUnsnappableIndicatorVisibility) {
5074 // Create three windows; two normal and one unsnappable, so that when after
5075 // snapping |window1| to enter split view we can test the state of each normal
5076 // and unsnappable windows.
5077 std::unique_ptr<aura::Window> window1(CreateTestWindow());
5078 std::unique_ptr<aura::Window> window2(CreateTestWindow());
5079 std::unique_ptr<aura::Window> unsnappable_window = CreateUnsnappableWindow();
5080
5081 ToggleOverview();
5082 ASSERT_TRUE(overview_controller()->InOverviewSession());
5083
5084 OverviewItem* snappable_overview_item =
5085 GetOverviewItemForWindow(window2.get());
5086 OverviewItem* unsnappable_overview_item =
5087 GetOverviewItemForWindow(unsnappable_window.get());
5088
5089 // Note: |cannot_snap_label_view_| and its parent will be created on demand.
5090 EXPECT_FALSE(snappable_overview_item->cannot_snap_widget_for_testing());
5091 ASSERT_FALSE(unsnappable_overview_item->cannot_snap_widget_for_testing());
5092
5093 // Snap the extra snappable window to enter split view mode.
5094 split_view_controller()->SnapWindow(window1.get(), SplitViewController::LEFT);
5095 ASSERT_TRUE(split_view_controller()->InSplitViewMode());
5096 EXPECT_FALSE(snappable_overview_item->cannot_snap_widget_for_testing());
5097 ASSERT_TRUE(unsnappable_overview_item->cannot_snap_widget_for_testing());
5098 ui::Layer* unsnappable_layer =
5099 unsnappable_overview_item->cannot_snap_widget_for_testing()
5100 ->GetNativeWindow()
5101 ->layer();
5102 EXPECT_EQ(1.f, unsnappable_layer->opacity());
5103
5104 // Exiting the splitview will hide the unsnappable label.
5105 const gfx::Rect divider_bounds =
5106 GetSplitViewDividerBounds(/*is_dragging=*/false);
5107 GetEventGenerator()->set_current_screen_location(
5108 divider_bounds.CenterPoint());
5109 GetEventGenerator()->DragMouseTo(0, 0);
5110 SkipDividerSnapAnimation();
5111
5112 EXPECT_FALSE(split_view_controller()->InSplitViewMode());
5113 EXPECT_EQ(0.f, unsnappable_layer->opacity());
5114 }
5115
5116 // Verify that during "normal" dragging from overview (not drag-to-close), the
5117 // dragged item's unsnappable indicator is temporarily suppressed.
TEST_P(SplitViewOverviewSessionTest,OverviewUnsnappableIndicatorVisibilityWhileDragging)5118 TEST_P(SplitViewOverviewSessionTest,
5119 OverviewUnsnappableIndicatorVisibilityWhileDragging) {
5120 ui::GestureConfiguration* gesture_config =
5121 ui::GestureConfiguration::GetInstance();
5122 gesture_config->set_long_press_time_in_ms(1);
5123 gesture_config->set_show_press_delay_in_ms(1);
5124
5125 std::unique_ptr<aura::Window> snapped_window = CreateTestWindow();
5126 std::unique_ptr<aura::Window> unsnappable_window = CreateUnsnappableWindow();
5127 ToggleOverview();
5128 ASSERT_TRUE(overview_controller()->InOverviewSession());
5129 split_view_controller()->SnapWindow(snapped_window.get(),
5130 SplitViewController::LEFT);
5131 ASSERT_TRUE(split_view_controller()->InSplitViewMode());
5132 OverviewItem* unsnappable_overview_item =
5133 GetOverviewItemForWindow(unsnappable_window.get());
5134 ASSERT_TRUE(unsnappable_overview_item->cannot_snap_widget_for_testing());
5135 ui::Layer* unsnappable_layer =
5136 unsnappable_overview_item->cannot_snap_widget_for_testing()
5137 ->GetNativeWindow()
5138 ->layer();
5139 ASSERT_EQ(1.f, unsnappable_layer->opacity());
5140
5141 // Test that the unsnappable label is temporarily suppressed during mouse
5142 // dragging.
5143 ui::test::EventGenerator* generator = GetEventGenerator();
5144 const gfx::Point drag_starting_point = gfx::ToRoundedPoint(
5145 unsnappable_overview_item->target_bounds().CenterPoint());
5146 generator->set_current_screen_location(drag_starting_point);
5147 generator->PressLeftButton();
5148 using DragBehavior = OverviewWindowDragController::DragBehavior;
5149 EXPECT_EQ(
5150 DragBehavior::kUndefined,
5151 overview_session()->window_drag_controller()->current_drag_behavior());
5152 EXPECT_EQ(1.f, unsnappable_layer->opacity());
5153 generator->MoveMouseBy(0, 20);
5154 EXPECT_EQ(
5155 DragBehavior::kNormalDrag,
5156 overview_session()->window_drag_controller()->current_drag_behavior());
5157 EXPECT_EQ(0.f, unsnappable_layer->opacity());
5158 generator->ReleaseLeftButton();
5159 EXPECT_EQ(1.f, unsnappable_layer->opacity());
5160
5161 // Test that the unsnappable label is temporarily suppressed during "normal"
5162 // touch dragging (not drag-to-close).
5163 generator->set_current_screen_location(drag_starting_point);
5164 generator->PressTouch();
5165 {
5166 base::RunLoop run_loop;
5167 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
5168 FROM_HERE, run_loop.QuitClosure(),
5169 base::TimeDelta::FromMilliseconds(2));
5170 run_loop.Run();
5171 }
5172 EXPECT_EQ(
5173 DragBehavior::kNormalDrag,
5174 overview_session()->window_drag_controller()->current_drag_behavior());
5175 EXPECT_EQ(0.f, unsnappable_layer->opacity());
5176 generator->MoveTouchBy(20, 0);
5177 generator->ReleaseTouch();
5178 EXPECT_EQ(1.f, unsnappable_layer->opacity());
5179
5180 // Test that the unsnappable label reappears if "normal" touch dragging (not
5181 // drag-to-close) ends when the item has not been actually dragged anywhere.
5182 // This case improves test coverage because it is handled in
5183 // |OverviewWindowDragController::ResetGesture| instead of
5184 // |OverviewWindowDragController::CompleteNormalDrag|.
5185 generator->set_current_screen_location(drag_starting_point);
5186 generator->PressTouch();
5187 {
5188 base::RunLoop run_loop;
5189 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
5190 FROM_HERE, run_loop.QuitClosure(),
5191 base::TimeDelta::FromMilliseconds(2));
5192 run_loop.Run();
5193 }
5194 EXPECT_EQ(
5195 DragBehavior::kNormalDrag,
5196 overview_session()->window_drag_controller()->current_drag_behavior());
5197 EXPECT_EQ(0.f, unsnappable_layer->opacity());
5198 generator->ReleaseTouch();
5199 EXPECT_EQ(1.f, unsnappable_layer->opacity());
5200
5201 // Test that the unsnappable label persists in drag-to-close mode.
5202 generator->set_current_screen_location(drag_starting_point);
5203 generator->PressTouch();
5204 // Use small increments otherwise a fling event will be fired.
5205 for (int j = 0; j < 20; ++j)
5206 generator->MoveTouchBy(0, 1);
5207 EXPECT_EQ(
5208 DragBehavior::kDragToClose,
5209 overview_session()->window_drag_controller()->current_drag_behavior());
5210 // Drag-to-close mode affects the opacity of the whole overview item,
5211 // including the unsnappable label.
5212 EXPECT_EQ(unsnappable_overview_item->GetWindow()->layer()->opacity(),
5213 unsnappable_layer->opacity());
5214 generator->ReleaseTouch();
5215 EXPECT_EQ(1.f, unsnappable_layer->opacity());
5216 }
5217
5218 // Verify that an item's unsnappable indicator is updated for display rotation.
TEST_P(SplitViewOverviewSessionTest,OverviewUnsnappableIndicatorVisibilityAfterDisplayRotation)5219 TEST_P(SplitViewOverviewSessionTest,
5220 OverviewUnsnappableIndicatorVisibilityAfterDisplayRotation) {
5221 UpdateDisplay("800x800");
5222 std::unique_ptr<aura::Window> snapped_window = CreateTestWindow();
5223 // Because of its minimum size, |overview_window| is snappable in horizontal
5224 // split view but not in vertical split view.
5225 std::unique_ptr<aura::Window> overview_window(
5226 CreateWindowWithMinimumSize(gfx::Rect(400, 600), gfx::Size(300, 500)));
5227 ToggleOverview();
5228 ASSERT_TRUE(overview_controller()->InOverviewSession());
5229 split_view_controller()->SnapWindow(snapped_window.get(),
5230 SplitViewController::LEFT);
5231 ASSERT_TRUE(split_view_controller()->InSplitViewMode());
5232 OverviewItem* overview_item = GetOverviewItemForWindow(overview_window.get());
5233 // Note: |cannot_snap_label_view_| and its parent will be created on demand.
5234 EXPECT_FALSE(overview_item->cannot_snap_widget_for_testing());
5235
5236 // Rotate to primary portrait orientation. The unsnappable indicator appears.
5237 display::test::DisplayManagerTestApi(Shell::Get()->display_manager())
5238 .SetFirstDisplayAsInternalDisplay();
5239 ScreenOrientationControllerTestApi test_api(
5240 Shell::Get()->screen_orientation_controller());
5241 test_api.SetDisplayRotation(display::Display::ROTATE_270,
5242 display::Display::RotationSource::ACTIVE);
5243 ASSERT_TRUE(overview_item->cannot_snap_widget_for_testing());
5244 ui::Layer* unsnappable_layer =
5245 overview_item->cannot_snap_widget_for_testing()->GetLayer();
5246 EXPECT_EQ(1.f, unsnappable_layer->opacity());
5247
5248 // Rotate to primary landscape orientation. The unsnappable indicator hides.
5249 test_api.SetDisplayRotation(display::Display::ROTATE_0,
5250 display::Display::RotationSource::ACTIVE);
5251 EXPECT_EQ(0.f, unsnappable_layer->opacity());
5252 }
5253
5254 // Test that when splitview mode and overview mode are both active at the same
5255 // time, dragging divider behaviors are correct.
TEST_P(SplitViewOverviewSessionTest,DragDividerToExitTest)5256 TEST_P(SplitViewOverviewSessionTest, DragDividerToExitTest) {
5257 UpdateDisplay("907x407");
5258
5259 const gfx::Rect bounds(400, 400);
5260 std::unique_ptr<aura::Window> window1(CreateWindow(bounds));
5261 std::unique_ptr<aura::Window> window2(CreateWindow(bounds));
5262 std::unique_ptr<aura::Window> window3(CreateWindow(bounds));
5263
5264 ToggleOverview();
5265
5266 // Drag |window1| selector item to snap to left.
5267 OverviewItem* overview_item1 = GetOverviewItemForWindow(window1.get());
5268 DragWindowTo(overview_item1, gfx::PointF());
5269 // Test that overview mode and split view mode are both active.
5270 EXPECT_TRUE(split_view_controller()->InSplitViewMode());
5271 EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
5272
5273 // Drag the divider toward closing the snapped window.
5274 gfx::Rect divider_bounds = GetSplitViewDividerBounds(false /* is_dragging */);
5275 split_view_controller()->StartResize(divider_bounds.CenterPoint());
5276 split_view_controller()->EndResize(gfx::Point(0, 0));
5277 SkipDividerSnapAnimation();
5278
5279 // Test that split view mode is ended. Overview mode is still active.
5280 EXPECT_FALSE(split_view_controller()->InSplitViewMode());
5281 EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
5282
5283 // Now drag |window2| selector item to snap to left.
5284 OverviewItem* overview_item2 = GetOverviewItemForWindow(window2.get());
5285 DragWindowTo(overview_item2, gfx::PointF());
5286 // Test that overview mode and split view mode are both active.
5287 EXPECT_TRUE(split_view_controller()->InSplitViewMode());
5288 EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
5289
5290 // Drag the divider toward closing the overview window grid.
5291 divider_bounds = GetSplitViewDividerBounds(false /*is_dragging=*/);
5292 const gfx::Rect display_bounds = GetWorkAreaInScreen(window2.get());
5293 split_view_controller()->StartResize(divider_bounds.CenterPoint());
5294 split_view_controller()->EndResize(display_bounds.bottom_right());
5295 SkipDividerSnapAnimation();
5296
5297 // Test that split view mode is ended. Overview mode is also ended. |window2|
5298 // should be activated.
5299 EXPECT_FALSE(split_view_controller()->InSplitViewMode());
5300 EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession());
5301 EXPECT_EQ(window2.get(), window_util::GetActiveWindow());
5302 }
5303
TEST_P(SplitViewOverviewSessionTest,OverviewItemLongPressed)5304 TEST_P(SplitViewOverviewSessionTest, OverviewItemLongPressed) {
5305 std::unique_ptr<aura::Window> window1 = CreateTestWindow();
5306 std::unique_ptr<aura::Window> window2 = CreateTestWindow();
5307
5308 ToggleOverview();
5309 ASSERT_TRUE(overview_controller()->InOverviewSession());
5310
5311 OverviewItem* overview_item = GetOverviewItemForWindow(window1.get());
5312 gfx::PointF start_location(overview_item->target_bounds().CenterPoint());
5313 const gfx::RectF original_bounds(overview_item->target_bounds());
5314
5315 // Verify that when a overview item receives a resetting gesture, we
5316 // stay in overview mode and the bounds of the item are the same as they were
5317 // before the press sequence started.
5318 overview_session()->InitiateDrag(overview_item, start_location,
5319 /*is_touch_dragging=*/true);
5320 overview_session()->ResetDraggedWindowGesture();
5321 EXPECT_TRUE(overview_controller()->InOverviewSession());
5322 EXPECT_EQ(original_bounds, overview_item->target_bounds());
5323
5324 // Verify that when a overview item is tapped, we exit overview mode,
5325 // and the current active window is the item.
5326 overview_session()->InitiateDrag(overview_item, start_location,
5327 /*is_touch_dragging=*/true);
5328 overview_session()->ActivateDraggedWindow();
5329 EXPECT_FALSE(overview_controller()->InOverviewSession());
5330 EXPECT_EQ(window1.get(), window_util::GetActiveWindow());
5331 }
5332
TEST_P(SplitViewOverviewSessionTest,SnappedWindowBoundsTest)5333 TEST_P(SplitViewOverviewSessionTest, SnappedWindowBoundsTest) {
5334 const gfx::Rect bounds(400, 400);
5335 const int kMinimumBoundSize = 100;
5336 const gfx::Size size(kMinimumBoundSize, kMinimumBoundSize);
5337
5338 std::unique_ptr<aura::Window> window1(
5339 CreateWindowWithMinimumSize(bounds, size));
5340 std::unique_ptr<aura::Window> window2(
5341 CreateWindowWithMinimumSize(bounds, size));
5342 std::unique_ptr<aura::Window> window3(
5343 CreateWindowWithMinimumSize(bounds, size));
5344 const int screen_width =
5345 screen_util::GetDisplayWorkAreaBoundsInParent(window1.get()).width();
5346 ToggleOverview();
5347
5348 // Drag |window1| selector item to snap to left.
5349 OverviewItem* overview_item1 = GetOverviewItemForWindow(window1.get());
5350 DragWindowTo(overview_item1, gfx::PointF());
5351 EXPECT_EQ(SplitViewController::State::kLeftSnapped,
5352 split_view_controller()->state());
5353 EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
5354
5355 // Then drag the divider to left toward closing the snapped window.
5356 gfx::Rect divider_bounds = GetSplitViewDividerBounds(false /*is_dragging=*/);
5357 split_view_controller()->StartResize(divider_bounds.CenterPoint());
5358 // Drag the divider to a point that is close enough but still have a short
5359 // distance to the edge of the screen.
5360 split_view_controller()->EndResize(gfx::Point(20, 20));
5361 SkipDividerSnapAnimation();
5362
5363 // Test that split view mode is ended. Overview mode is still active.
5364 EXPECT_FALSE(split_view_controller()->InSplitViewMode());
5365 EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
5366 // Test that |window1| has the dimensions of a tablet mode maxed window, so
5367 // that when it is placed back on the grid it will not look skinny.
5368 EXPECT_LE(window1->bounds().x(), 0);
5369 EXPECT_EQ(window1->bounds().width(), screen_width);
5370
5371 // Drag |window2| selector item to snap to right.
5372 OverviewItem* overview_item2 = GetOverviewItemForWindow(window2.get());
5373 const gfx::Rect work_area_rect = GetWorkAreaInScreen(window2.get());
5374 gfx::Point end_location2 =
5375 gfx::Point(work_area_rect.width(), work_area_rect.height());
5376 DragWindowTo(overview_item2, gfx::PointF(end_location2));
5377 EXPECT_EQ(SplitViewController::State::kRightSnapped,
5378 split_view_controller()->state());
5379 EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
5380
5381 // Then drag the divider to right toward closing the snapped window.
5382 divider_bounds = GetSplitViewDividerBounds(false /* is_dragging */);
5383 split_view_controller()->StartResize(divider_bounds.CenterPoint());
5384 // Drag the divider to a point that is close enough but still have a short
5385 // distance to the edge of the screen.
5386 end_location2.Offset(-20, -20);
5387 split_view_controller()->EndResize(end_location2);
5388 SkipDividerSnapAnimation();
5389
5390 // Test that split view mode is ended. Overview mode is still active.
5391 EXPECT_FALSE(split_view_controller()->InSplitViewMode());
5392 EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
5393 // Test that |window2| has the dimensions of a tablet mode maxed window, so
5394 // that when it is placed back on the grid it will not look skinny.
5395 EXPECT_GE(window2->bounds().x(), 0);
5396 EXPECT_EQ(window2->bounds().width(), screen_width);
5397 }
5398
5399 // Test snapped window bounds with adjustment for the minimum size of a window.
TEST_P(SplitViewOverviewSessionTest,SnappedWindowBoundsWithMinimumSizeTest)5400 TEST_P(SplitViewOverviewSessionTest, SnappedWindowBoundsWithMinimumSizeTest) {
5401 const gfx::Rect bounds(400, 400);
5402 std::unique_ptr<aura::Window> window1(CreateTestWindow(bounds));
5403 const int work_area_length =
5404 screen_util::GetDisplayWorkAreaBoundsInScreenForActiveDeskContainer(
5405 Shell::GetPrimaryRootWindow())
5406 .width();
5407 std::unique_ptr<aura::Window> window2(CreateWindowWithMinimumSize(
5408 bounds, gfx::Size(work_area_length / 3 + 20, 0)));
5409
5410 ToggleOverview();
5411 split_view_controller()->SnapWindow(window1.get(), SplitViewController::LEFT);
5412 split_view_controller()->StartResize(
5413 GetSplitViewDividerBounds(/*is_dragging=*/false).CenterPoint());
5414 split_view_controller()->EndResize(gfx::Point(work_area_length / 3, 10));
5415 SkipDividerSnapAnimation();
5416 // Use |EXPECT_NEAR| for reasons related to rounding and divider thickness.
5417 EXPECT_NEAR(
5418 work_area_length / 3,
5419 split_view_controller()
5420 ->GetSnappedWindowBoundsInScreen(SplitViewController::LEFT,
5421 /*window_for_minimum_size=*/nullptr)
5422 .width(),
5423 8);
5424 EXPECT_NEAR(work_area_length / 2,
5425 split_view_controller()
5426 ->GetSnappedWindowBoundsInScreen(SplitViewController::LEFT,
5427 window2.get())
5428 .width(),
5429 8);
5430 EXPECT_NEAR(
5431 work_area_length * 2 / 3,
5432 split_view_controller()
5433 ->GetSnappedWindowBoundsInScreen(SplitViewController::RIGHT,
5434 /*window_for_minimum_size=*/nullptr)
5435 .width(),
5436 8);
5437 EXPECT_NEAR(work_area_length * 2 / 3,
5438 split_view_controller()
5439 ->GetSnappedWindowBoundsInScreen(SplitViewController::RIGHT,
5440 window2.get())
5441 .width(),
5442 8);
5443 split_view_controller()->StartResize(
5444 GetSplitViewDividerBounds(/*is_dragging=*/false).CenterPoint());
5445 split_view_controller()->EndResize(gfx::Point(work_area_length * 2 / 3, 10));
5446 EXPECT_NEAR(
5447 work_area_length * 2 / 3,
5448 split_view_controller()
5449 ->GetSnappedWindowBoundsInScreen(SplitViewController::LEFT,
5450 /*window_for_minimum_size=*/nullptr)
5451 .width(),
5452 8);
5453 EXPECT_NEAR(work_area_length * 2 / 3,
5454 split_view_controller()
5455 ->GetSnappedWindowBoundsInScreen(SplitViewController::LEFT,
5456 window2.get())
5457 .width(),
5458 8);
5459 EXPECT_NEAR(
5460 work_area_length / 3,
5461 split_view_controller()
5462 ->GetSnappedWindowBoundsInScreen(SplitViewController::RIGHT,
5463 /*window_for_minimum_size=*/nullptr)
5464 .width(),
5465 8);
5466 EXPECT_NEAR(work_area_length / 2,
5467 split_view_controller()
5468 ->GetSnappedWindowBoundsInScreen(SplitViewController::RIGHT,
5469 window2.get())
5470 .width(),
5471 8);
5472 }
5473
5474 // Verify that if the split view divider is dragged all the way to the edge, the
5475 // window being dragged gets returned to the overview list, if overview mode is
5476 // still active.
TEST_P(SplitViewOverviewSessionTest,DividerDraggedToEdgeReturnsWindowToOverviewList)5477 TEST_P(SplitViewOverviewSessionTest,
5478 DividerDraggedToEdgeReturnsWindowToOverviewList) {
5479 const gfx::Rect bounds(400, 400);
5480 std::unique_ptr<aura::Window> window1(CreateWindow(bounds));
5481 std::unique_ptr<aura::Window> window2(CreateWindow(bounds));
5482 std::unique_ptr<aura::Window> window3(CreateWindow(bounds));
5483
5484 ToggleOverview();
5485 // Drag |window1| selector item to snap to left. There should be two items on
5486 // the overview grid afterwards, |window2| and |window3|.
5487 OverviewItem* overview_item1 = GetOverviewItemForWindow(window1.get());
5488 DragWindowTo(overview_item1, gfx::PointF());
5489 EXPECT_EQ(SplitViewController::State::kLeftSnapped,
5490 split_view_controller()->state());
5491 EXPECT_TRUE(InOverviewSession());
5492 EXPECT_TRUE(split_view_controller()->InSplitViewMode());
5493 ASSERT_TRUE(split_view_controller()->split_view_divider());
5494 std::vector<aura::Window*> window_list =
5495 overview_controller()->GetWindowsListInOverviewGridsForTest();
5496 EXPECT_EQ(2u, window_list.size());
5497 EXPECT_FALSE(base::Contains(window_list, window1.get()));
5498 EXPECT_TRUE(wm::IsActiveWindow(window1.get()));
5499
5500 // Drag the divider to the left edge.
5501 const gfx::Rect divider_bounds =
5502 GetSplitViewDividerBounds(/*is_dragging=*/false);
5503 GetEventGenerator()->set_current_screen_location(
5504 divider_bounds.CenterPoint());
5505 GetEventGenerator()->DragMouseTo(0, 0);
5506 SkipDividerSnapAnimation();
5507
5508 // Verify that it is still in overview mode and that |window1| is returned to
5509 // the overview list.
5510 EXPECT_TRUE(InOverviewSession());
5511 EXPECT_FALSE(split_view_controller()->InSplitViewMode());
5512 window_list = overview_controller()->GetWindowsListInOverviewGridsForTest();
5513 EXPECT_EQ(3u, window_list.size());
5514 EXPECT_TRUE(base::Contains(window_list, window1.get()));
5515 EXPECT_FALSE(wm::IsActiveWindow(window1.get()));
5516 }
5517
5518 // Verify that if overview mode is active and the split view divider is dragged
5519 // all the way to the opposite edge, then the split view window is reinserted
5520 // into the overview grid at the correct position according to MRU order, and
5521 // the stacking order is also correct.
TEST_P(SplitViewOverviewSessionTest,SplitViewWindowReinsertedToOverviewAtCorrectPositionWhenSplitViewIsEnded)5522 TEST_P(
5523 SplitViewOverviewSessionTest,
5524 SplitViewWindowReinsertedToOverviewAtCorrectPositionWhenSplitViewIsEnded) {
5525 const gfx::Rect bounds(400, 400);
5526 std::unique_ptr<aura::Window> window1(CreateWindow(bounds));
5527 std::unique_ptr<aura::Window> window2(CreateWindow(bounds));
5528 std::unique_ptr<aura::Window> window3(CreateWindow(bounds));
5529 ToggleOverview();
5530 DragWindowTo(GetOverviewItemForWindow(window1.get()), gfx::PointF());
5531 DragWindowTo(GetOverviewItemForWindow(window2.get()),
5532 gfx::PointF(799.f, 0.f));
5533 EXPECT_EQ(window1.get(), split_view_controller()->left_window());
5534 EXPECT_EQ(window2.get(), split_view_controller()->right_window());
5535 ToggleOverview();
5536 // Drag the divider to the left edge.
5537 const gfx::Rect divider_bounds =
5538 GetSplitViewDividerBounds(/*is_dragging=*/false);
5539 GetEventGenerator()->set_current_screen_location(
5540 divider_bounds.CenterPoint());
5541 GetEventGenerator()->DragMouseTo(0, 0);
5542 SkipDividerSnapAnimation();
5543
5544 // Verify the grid arrangement.
5545 ASSERT_TRUE(InOverviewSession());
5546 const std::vector<aura::Window*> expected_mru_list = {
5547 window2.get(), window1.get(), window3.get()};
5548 const std::vector<aura::Window*> expected_overview_list = {
5549 window2.get(), window1.get(), window3.get()};
5550 EXPECT_EQ(
5551 expected_mru_list,
5552 Shell::Get()->mru_window_tracker()->BuildMruWindowList(kActiveDesk));
5553 EXPECT_EQ(expected_overview_list,
5554 overview_controller()->GetWindowsListInOverviewGridsForTest());
5555
5556 // Verify the stacking order.
5557 aura::Window* parent = window1->parent();
5558 ASSERT_EQ(parent, window2->parent());
5559 ASSERT_EQ(parent, window3->parent());
5560 EXPECT_GT(IndexOf(GetOverviewItemForWindow(window2.get())
5561 ->item_widget()
5562 ->GetNativeWindow(),
5563 parent),
5564 IndexOf(GetOverviewItemForWindow(window1.get())
5565 ->item_widget()
5566 ->GetNativeWindow(),
5567 parent));
5568 EXPECT_GT(IndexOf(GetOverviewItemForWindow(window1.get())
5569 ->item_widget()
5570 ->GetNativeWindow(),
5571 parent),
5572 IndexOf(GetOverviewItemForWindow(window3.get())
5573 ->item_widget()
5574 ->GetNativeWindow(),
5575 parent));
5576 }
5577
5578 // Verify that if a window is dragged from overview and snapped in place of
5579 // another split view window, then the old split view window is reinserted into
5580 // the overview grid at the correct position according to MRU order, and the
5581 // stacking order is also correct.
TEST_P(SplitViewOverviewSessionTest,SplitViewWindowReinsertedToOverviewAtCorrectPositionWhenAnotherWindowTakesItsPlace)5582 TEST_P(
5583 SplitViewOverviewSessionTest,
5584 SplitViewWindowReinsertedToOverviewAtCorrectPositionWhenAnotherWindowTakesItsPlace) {
5585 const gfx::Rect bounds(400, 400);
5586 std::unique_ptr<aura::Window> window1(CreateWindow(bounds));
5587 std::unique_ptr<aura::Window> window2(CreateWindow(bounds));
5588 std::unique_ptr<aura::Window> window3(CreateWindow(bounds));
5589 std::unique_ptr<aura::Window> window4(CreateWindow(bounds));
5590 ToggleOverview();
5591 DragWindowTo(GetOverviewItemForWindow(window1.get()), gfx::PointF());
5592 DragWindowTo(GetOverviewItemForWindow(window2.get()),
5593 gfx::PointF(799.f, 0.f));
5594 EXPECT_EQ(window1.get(), split_view_controller()->left_window());
5595 EXPECT_EQ(window2.get(), split_view_controller()->right_window());
5596 ToggleOverview();
5597 DragWindowTo(GetOverviewItemForWindow(window3.get()), gfx::PointF());
5598 EXPECT_EQ(window3.get(), split_view_controller()->left_window());
5599
5600 // Verify the grid arrangement.
5601 ASSERT_TRUE(InOverviewSession());
5602 const std::vector<aura::Window*> expected_mru_list = {
5603 window3.get(), window2.get(), window1.get(), window4.get()};
5604 const std::vector<aura::Window*> expected_overview_list = {
5605 window2.get(), window1.get(), window4.get()};
5606 EXPECT_EQ(
5607 expected_mru_list,
5608 Shell::Get()->mru_window_tracker()->BuildMruWindowList(kActiveDesk));
5609 EXPECT_EQ(expected_overview_list,
5610 overview_controller()->GetWindowsListInOverviewGridsForTest());
5611
5612 // Verify the stacking order.
5613 aura::Window* parent = window1->parent();
5614 ASSERT_EQ(parent, window2->parent());
5615 ASSERT_EQ(parent, window4->parent());
5616 EXPECT_GT(IndexOf(GetOverviewItemForWindow(window2.get())
5617 ->item_widget()
5618 ->GetNativeWindow(),
5619 parent),
5620 IndexOf(GetOverviewItemForWindow(window1.get())
5621 ->item_widget()
5622 ->GetNativeWindow(),
5623 parent));
5624 EXPECT_GT(IndexOf(GetOverviewItemForWindow(window1.get())
5625 ->item_widget()
5626 ->GetNativeWindow(),
5627 parent),
5628 IndexOf(GetOverviewItemForWindow(window4.get())
5629 ->item_widget()
5630 ->GetNativeWindow(),
5631 parent));
5632 }
5633
5634 // Verify that if the split view divider is dragged close to the edge, the grid
5635 // bounds will be fixed to a third of the work area width and start sliding off
5636 // the screen instead of continuing to shrink.
TEST_P(SplitViewOverviewSessionTest,OverviewHasMinimumBoundsWhenDividerDragged)5637 TEST_P(SplitViewOverviewSessionTest,
5638 OverviewHasMinimumBoundsWhenDividerDragged) {
5639 UpdateDisplay("600x400");
5640
5641 const gfx::Rect bounds(400, 400);
5642 std::unique_ptr<aura::Window> window1(CreateWindow(bounds));
5643 std::unique_ptr<aura::Window> window2(CreateWindow(bounds));
5644
5645 ToggleOverview();
5646 // Snap a window to the left and test dragging the divider towards the right
5647 // edge of the screen.
5648 split_view_controller()->SnapWindow(window1.get(), SplitViewController::LEFT);
5649 OverviewGrid* grid = overview_session()->grid_list()[0].get();
5650 ASSERT_TRUE(grid);
5651
5652 // Drag the divider to the right edge.
5653 gfx::Rect divider_bounds = GetSplitViewDividerBounds(/*is_dragging=*/false);
5654 ui::test::EventGenerator* generator = GetEventGenerator();
5655 generator->set_current_screen_location(divider_bounds.CenterPoint());
5656 generator->PressLeftButton();
5657
5658 // Tests that near the right edge, the grid bounds are fixed at 200 and are
5659 // partially off screen to the right.
5660 generator->MoveMouseTo(580, 0);
5661 EXPECT_EQ(200, grid->bounds().width());
5662 EXPECT_GT(grid->bounds().right(), 600);
5663 generator->ReleaseLeftButton();
5664 SkipDividerSnapAnimation();
5665
5666 // Releasing close to the edge will activate the left window and exit
5667 // overview.
5668 ASSERT_FALSE(InOverviewSession());
5669 ToggleOverview();
5670 // Snap a window to the right and test dragging the divider towards the left
5671 // edge of the screen.
5672 split_view_controller()->SnapWindow(window1.get(),
5673 SplitViewController::RIGHT);
5674 grid = overview_session()->grid_list()[0].get();
5675 ASSERT_TRUE(grid);
5676
5677 // Drag the divider to the left edge.
5678 divider_bounds = GetSplitViewDividerBounds(/*is_dragging=*/false);
5679 generator->set_current_screen_location(divider_bounds.CenterPoint());
5680 generator->PressLeftButton();
5681
5682 generator->MoveMouseTo(20, 0);
5683 // Tests that near the left edge, the grid bounds are fixed at 200 and are
5684 // partially off screen to the left.
5685 EXPECT_EQ(200, grid->bounds().width());
5686 EXPECT_LT(grid->bounds().x(), 0);
5687 generator->ReleaseLeftButton();
5688 SkipDividerSnapAnimation();
5689 }
5690
5691 // Test that when splitview mode is active, minimizing one of the snapped window
5692 // will insert the minimized window back to overview mode if overview mode is
5693 // active at the moment.
TEST_P(SplitViewOverviewSessionTest,InsertMinimizedWindowBackToOverview)5694 TEST_P(SplitViewOverviewSessionTest, InsertMinimizedWindowBackToOverview) {
5695 const gfx::Rect bounds(400, 400);
5696 std::unique_ptr<aura::Window> window1(CreateWindow(bounds));
5697 std::unique_ptr<aura::Window> window2(CreateWindow(bounds));
5698
5699 ToggleOverview();
5700 OverviewItem* overview_item1 = GetOverviewItemForWindow(window1.get());
5701 DragWindowTo(overview_item1, gfx::PointF());
5702 EXPECT_EQ(split_view_controller()->state(),
5703 SplitViewController::State::kLeftSnapped);
5704 EXPECT_EQ(split_view_controller()->left_window(), window1.get());
5705 EXPECT_TRUE(InOverviewSession());
5706
5707 // Minimize |window1| will put |window1| back to overview grid.
5708 WindowState::Get(window1.get())->Minimize();
5709 EXPECT_FALSE(split_view_controller()->InSplitViewMode());
5710 EXPECT_TRUE(InOverviewSession());
5711 EXPECT_TRUE(GetOverviewItemForWindow(window1.get()));
5712
5713 // Now snap both |window1| and |window2|.
5714 overview_item1 = GetOverviewItemForWindow(window1.get());
5715 DragWindowTo(overview_item1, gfx::PointF());
5716 wm::ActivateWindow(window2.get());
5717 EXPECT_FALSE(InOverviewSession());
5718 EXPECT_EQ(split_view_controller()->state(),
5719 SplitViewController::State::kBothSnapped);
5720 EXPECT_EQ(split_view_controller()->left_window(), window1.get());
5721 EXPECT_EQ(split_view_controller()->right_window(), window2.get());
5722
5723 // Minimize |window1| will open overview and put |window1| to overview grid.
5724 WindowState::Get(window1.get())->Minimize();
5725 EXPECT_TRUE(split_view_controller()->InSplitViewMode());
5726 EXPECT_EQ(split_view_controller()->state(),
5727 SplitViewController::State::kRightSnapped);
5728 EXPECT_TRUE(InOverviewSession());
5729 EXPECT_TRUE(GetOverviewItemForWindow(window1.get()));
5730
5731 // Minimize |window2| also put |window2| to overview grid.
5732 WindowState::Get(window2.get())->Minimize();
5733 EXPECT_FALSE(split_view_controller()->InSplitViewMode());
5734 EXPECT_TRUE(InOverviewSession());
5735 EXPECT_TRUE(GetOverviewItemForWindow(window1.get()));
5736 EXPECT_TRUE(GetOverviewItemForWindow(window2.get()));
5737 }
5738
5739 // Test that when splitview and overview are both active at the same time, if
5740 // overview is ended due to snapping a window in splitview, the tranform of each
5741 // window in the overview grid is restored.
TEST_P(SplitViewOverviewSessionTest,SnappedWindowAnimationObserverTest)5742 TEST_P(SplitViewOverviewSessionTest, SnappedWindowAnimationObserverTest) {
5743 const gfx::Rect bounds(400, 400);
5744 std::unique_ptr<aura::Window> window1(CreateWindow(bounds));
5745 std::unique_ptr<aura::Window> window2(CreateWindow(bounds));
5746 std::unique_ptr<aura::Window> window3(CreateWindow(bounds));
5747
5748 // There are four ways to exit overview mode. Verify in each case the
5749 // tranform of each window in the overview window grid has been restored.
5750
5751 // 1. Overview is ended by dragging a item in overview to snap to splitview.
5752 // Drag |window1| selector item to snap to left. There should be two items on
5753 // the overview grid afterwards, |window2| and |window3|.
5754 ToggleOverview();
5755 EXPECT_FALSE(window1->layer()->GetTargetTransform().IsIdentity());
5756 EXPECT_FALSE(window2->layer()->GetTargetTransform().IsIdentity());
5757 EXPECT_FALSE(window3->layer()->GetTargetTransform().IsIdentity());
5758 OverviewItem* overview_item1 = GetOverviewItemForWindow(window1.get());
5759 DragWindowTo(overview_item1, gfx::PointF());
5760 EXPECT_EQ(SplitViewController::State::kLeftSnapped,
5761 split_view_controller()->state());
5762 // Drag |window2| to snap to right.
5763 OverviewItem* overview_item2 = GetOverviewItemForWindow(window2.get());
5764 const gfx::Rect work_area_rect =
5765 screen_util::GetDisplayWorkAreaBoundsInScreenForActiveDeskContainer(
5766 window2.get());
5767 const gfx::PointF end_location2(work_area_rect.width(), 0);
5768 DragWindowTo(overview_item2, end_location2);
5769 EXPECT_EQ(SplitViewController::State::kBothSnapped,
5770 split_view_controller()->state());
5771 EXPECT_FALSE(overview_controller()->InOverviewSession());
5772 EXPECT_TRUE(window1->layer()->GetTargetTransform().IsIdentity());
5773 EXPECT_TRUE(window2->layer()->GetTargetTransform().IsIdentity());
5774 EXPECT_TRUE(window3->layer()->GetTargetTransform().IsIdentity());
5775
5776 // 2. Overview is ended by ToggleOverview() directly.
5777 // ToggleOverview() will open overview grid in the non-default side of the
5778 // split screen.
5779 ToggleOverview();
5780 EXPECT_TRUE(window1->layer()->GetTargetTransform().IsIdentity());
5781 EXPECT_FALSE(window2->layer()->GetTargetTransform().IsIdentity());
5782 EXPECT_FALSE(window3->layer()->GetTargetTransform().IsIdentity());
5783 EXPECT_EQ(SplitViewController::State::kLeftSnapped,
5784 split_view_controller()->state());
5785 // ToggleOverview() directly.
5786 ToggleOverview();
5787 EXPECT_EQ(SplitViewController::State::kBothSnapped,
5788 split_view_controller()->state());
5789 EXPECT_FALSE(overview_controller()->InOverviewSession());
5790 EXPECT_TRUE(window1->layer()->GetTargetTransform().IsIdentity());
5791 EXPECT_TRUE(window2->layer()->GetTargetTransform().IsIdentity());
5792 EXPECT_TRUE(window3->layer()->GetTargetTransform().IsIdentity());
5793
5794 // 3. Overview is ended by actviating an existing window.
5795 ToggleOverview();
5796 EXPECT_TRUE(window1->layer()->GetTargetTransform().IsIdentity());
5797 EXPECT_FALSE(window2->layer()->GetTargetTransform().IsIdentity());
5798 EXPECT_FALSE(window3->layer()->GetTargetTransform().IsIdentity());
5799 EXPECT_EQ(SplitViewController::State::kLeftSnapped,
5800 split_view_controller()->state());
5801 wm::ActivateWindow(window2.get());
5802 EXPECT_EQ(SplitViewController::State::kBothSnapped,
5803 split_view_controller()->state());
5804 EXPECT_FALSE(overview_controller()->InOverviewSession());
5805 EXPECT_TRUE(window1->layer()->GetTargetTransform().IsIdentity());
5806 EXPECT_TRUE(window2->layer()->GetTargetTransform().IsIdentity());
5807 EXPECT_TRUE(window3->layer()->GetTargetTransform().IsIdentity());
5808
5809 // 4. Overview is ended by activating a new window.
5810 ToggleOverview();
5811 EXPECT_TRUE(window1->layer()->GetTargetTransform().IsIdentity());
5812 EXPECT_FALSE(window2->layer()->GetTargetTransform().IsIdentity());
5813 EXPECT_FALSE(window3->layer()->GetTargetTransform().IsIdentity());
5814 EXPECT_EQ(SplitViewController::State::kLeftSnapped,
5815 split_view_controller()->state());
5816 std::unique_ptr<aura::Window> window4(CreateWindow(bounds));
5817 wm::ActivateWindow(window4.get());
5818 EXPECT_EQ(SplitViewController::State::kBothSnapped,
5819 split_view_controller()->state());
5820 EXPECT_FALSE(overview_controller()->InOverviewSession());
5821 EXPECT_TRUE(window1->layer()->GetTargetTransform().IsIdentity());
5822 EXPECT_TRUE(window2->layer()->GetTargetTransform().IsIdentity());
5823 EXPECT_TRUE(window3->layer()->GetTargetTransform().IsIdentity());
5824 EXPECT_TRUE(window4->layer()->GetTargetTransform().IsIdentity());
5825 }
5826
5827 // Test that when split view and overview are both active at the same time,
5828 // double tapping on the divider can swap the window's position with the
5829 // overview window grid's postion.
TEST_P(SplitViewOverviewSessionTest,SwapWindowAndOverviewGrid)5830 TEST_P(SplitViewOverviewSessionTest, SwapWindowAndOverviewGrid) {
5831 const gfx::Rect bounds(400, 400);
5832 std::unique_ptr<aura::Window> window1(CreateWindow(bounds));
5833 std::unique_ptr<aura::Window> window2(CreateWindow(bounds));
5834
5835 ToggleOverview();
5836 OverviewItem* overview_item1 = GetOverviewItemForWindow(window1.get());
5837 DragWindowTo(overview_item1, gfx::PointF());
5838 EXPECT_EQ(split_view_controller()->state(),
5839 SplitViewController::State::kLeftSnapped);
5840 EXPECT_EQ(split_view_controller()->default_snap_position(),
5841 SplitViewController::LEFT);
5842 EXPECT_TRUE(overview_controller()->InOverviewSession());
5843 EXPECT_EQ(
5844 GetGridBounds(),
5845 split_view_controller()->GetSnappedWindowBoundsInScreen(
5846 SplitViewController::RIGHT, /*window_for_minimum_size=*/nullptr));
5847
5848 split_view_controller()->SwapWindows();
5849 EXPECT_EQ(split_view_controller()->state(),
5850 SplitViewController::State::kRightSnapped);
5851 EXPECT_EQ(split_view_controller()->default_snap_position(),
5852 SplitViewController::RIGHT);
5853 EXPECT_EQ(
5854 GetGridBounds(),
5855 split_view_controller()->GetSnappedWindowBoundsInScreen(
5856 SplitViewController::LEFT, /*window_for_minimum_size=*/nullptr));
5857 }
5858
5859 // Test that in tablet mode, pressing tab key in overview should not crash.
TEST_P(SplitViewOverviewSessionTest,NoCrashWhenPressTabKey)5860 TEST_P(SplitViewOverviewSessionTest, NoCrashWhenPressTabKey) {
5861 std::unique_ptr<aura::Window> window(CreateWindow(gfx::Rect(400, 400)));
5862 std::unique_ptr<aura::Window> window2(CreateWindow(gfx::Rect(400, 400)));
5863
5864 // In overview, there should be no crash when pressing tab key.
5865 ToggleOverview();
5866 EXPECT_TRUE(InOverviewSession());
5867 SendKey(ui::VKEY_TAB);
5868 EXPECT_TRUE(InOverviewSession());
5869
5870 // When splitview and overview are both active, there should be no crash when
5871 // pressing tab key.
5872 split_view_controller()->SnapWindow(window.get(), SplitViewController::LEFT);
5873 EXPECT_TRUE(InOverviewSession());
5874 EXPECT_TRUE(split_view_controller()->InSplitViewMode());
5875
5876 SendKey(ui::VKEY_TAB);
5877 EXPECT_TRUE(InOverviewSession());
5878 }
5879
5880 // Tests closing a snapped window while in overview mode.
TEST_P(SplitViewOverviewSessionTest,ClosingSplitViewWindow)5881 TEST_P(SplitViewOverviewSessionTest, ClosingSplitViewWindow) {
5882 const gfx::Rect bounds(400, 400);
5883 std::unique_ptr<aura::Window> window1(CreateWindow(bounds));
5884 std::unique_ptr<aura::Window> window2(CreateWindow(bounds));
5885
5886 ToggleOverview();
5887 // Drag |window1| selector item to snap to left.
5888 OverviewItem* overview_item1 = GetOverviewItemForWindow(window1.get());
5889 DragWindowTo(overview_item1, gfx::PointF(0, 0));
5890 EXPECT_TRUE(overview_controller()->InOverviewSession());
5891 EXPECT_TRUE(split_view_controller()->InSplitViewMode());
5892
5893 // Now close the snapped |window1|. We should remain in overview mode and the
5894 // overview focus window should regain focus.
5895 window1.reset();
5896 EXPECT_TRUE(overview_controller()->InOverviewSession());
5897 EXPECT_FALSE(split_view_controller()->InSplitViewMode());
5898 EXPECT_EQ(overview_session()->GetOverviewFocusWindow(),
5899 window_util::GetFocusedWindow());
5900 }
5901
5902 // Test that you cannot drag from overview during the split view divider
5903 // animation.
TEST_P(SplitViewOverviewSessionTest,CannotDragFromOverviewDuringSplitViewDividerAnimation)5904 TEST_P(SplitViewOverviewSessionTest,
5905 CannotDragFromOverviewDuringSplitViewDividerAnimation) {
5906 std::unique_ptr<aura::Window> snapped_window = CreateTestWindow();
5907 std::unique_ptr<aura::Window> overview_window = CreateTestWindow();
5908 ToggleOverview();
5909 split_view_controller()->SnapWindow(snapped_window.get(),
5910 SplitViewController::LEFT);
5911
5912 gfx::Point divider_drag_point =
5913 split_view_controller()
5914 ->split_view_divider()
5915 ->GetDividerBoundsInScreen(/*is_dragging=*/false)
5916 .CenterPoint();
5917 split_view_controller()->StartResize(divider_drag_point);
5918 divider_drag_point.Offset(20, 0);
5919 split_view_controller()->Resize(divider_drag_point);
5920 split_view_controller()->EndResize(divider_drag_point);
5921 ASSERT_TRUE(IsDividerAnimating());
5922
5923 OverviewItem* overview_item = GetOverviewItemForWindow(overview_window.get());
5924 overview_session()->InitiateDrag(overview_item,
5925 overview_item->target_bounds().CenterPoint(),
5926 /*is_touch_dragging=*/true);
5927 EXPECT_FALSE(overview_item->IsDragItem());
5928 }
5929
5930 // Tests that a window which is dragged to a splitview zone is destroyed, the
5931 // grid bounds return to a non-splitview bounds.
TEST_P(SplitViewOverviewSessionTest,GridBoundsAfterWindowDestroyed)5932 TEST_P(SplitViewOverviewSessionTest, GridBoundsAfterWindowDestroyed) {
5933 // Create two windows otherwise we exit overview after one window is
5934 // destroyed.
5935 std::unique_ptr<aura::Window> window1 = CreateTestWindow();
5936 std::unique_ptr<aura::Window> window2 = CreateTestWindow();
5937
5938 ToggleOverview();
5939 const gfx::Rect grid_bounds = GetGridBounds();
5940 // Drag the item such that the splitview preview area shows up and the grid
5941 // bounds shrink.
5942 OverviewItem* overview_item = GetOverviewItemForWindow(window1.get());
5943 overview_session()->InitiateDrag(overview_item,
5944 overview_item->target_bounds().CenterPoint(),
5945 /*is_touch_dragging=*/true);
5946 overview_session()->Drag(overview_item, gfx::PointF(1.f, 1.f));
5947 EXPECT_NE(grid_bounds, GetGridBounds());
5948
5949 // Tests that when the dragged window is destroyed, the grid bounds return to
5950 // their normal size.
5951 window1.reset();
5952 EXPECT_EQ(grid_bounds, GetGridBounds());
5953 }
5954
5955 // Tests that overview stays active if we have a snapped window.
TEST_P(SplitViewOverviewSessionTest,OnScreenLock)5956 TEST_P(SplitViewOverviewSessionTest, OnScreenLock) {
5957 std::unique_ptr<aura::Window> window1 = CreateTestWindow();
5958 std::unique_ptr<aura::Window> window2 = CreateTestWindow();
5959
5960 // Overview should exit if no snapped window after locking/unlocking.
5961 ToggleOverview();
5962 GetSessionControllerClient()->LockScreen();
5963 GetSessionControllerClient()->UnlockScreen();
5964 ASSERT_FALSE(InOverviewSession());
5965
5966 ToggleOverview();
5967 split_view_controller()->SnapWindow(window2.get(), SplitViewController::LEFT);
5968
5969 // Lock and unlock the machine. Test that we are still in overview and
5970 // splitview.
5971 GetSessionControllerClient()->LockScreen();
5972 GetSessionControllerClient()->UnlockScreen();
5973 EXPECT_TRUE(InOverviewSession());
5974 EXPECT_EQ(SplitViewController::State::kLeftSnapped,
5975 split_view_controller()->state());
5976 }
5977
5978 // Verify that selecting an minimized snappable window while in split view
5979 // triggers auto snapping.
TEST_P(SplitViewOverviewSessionTest,SelectMinimizedSnappableWindowInSplitView)5980 TEST_P(SplitViewOverviewSessionTest,
5981 SelectMinimizedSnappableWindowInSplitView) {
5982 // Create two snappable windows.
5983 std::unique_ptr<aura::Window> snapped_window = CreateTestWindow();
5984 std::unique_ptr<aura::Window> minimized_window = CreateTestWindow();
5985 WindowState::Get(minimized_window.get())->Minimize();
5986
5987 ToggleOverview();
5988 ASSERT_TRUE(overview_controller()->InOverviewSession());
5989
5990 // Snap a window to enter split view mode.
5991 split_view_controller()->SnapWindow(snapped_window.get(),
5992 SplitViewController::LEFT);
5993 EXPECT_EQ(SplitViewController::State::kLeftSnapped,
5994 split_view_controller()->state());
5995
5996 // Select the minimized window.
5997 OverviewItem* overview_item =
5998 GetOverviewItemForWindow(minimized_window.get());
5999 ui::test::EventGenerator* generator = GetEventGenerator();
6000 generator->set_current_screen_location(
6001 gfx::ToRoundedPoint(overview_item->target_bounds().CenterPoint()));
6002 generator->ClickLeftButton();
6003
6004 // Verify that both windows are in a snapped state and overview mode is ended.
6005 EXPECT_TRUE(split_view_controller()->InSplitViewMode());
6006 EXPECT_TRUE(
6007 split_view_controller()->IsWindowInSplitView(snapped_window.get()));
6008 EXPECT_EQ(
6009 split_view_controller()->GetPositionOfSnappedWindow(snapped_window.get()),
6010 SplitViewController::LEFT);
6011 EXPECT_TRUE(
6012 split_view_controller()->IsWindowInSplitView(minimized_window.get()));
6013 EXPECT_EQ(split_view_controller()->GetPositionOfSnappedWindow(
6014 minimized_window.get()),
6015 SplitViewController::RIGHT);
6016 EXPECT_FALSE(overview_controller()->InOverviewSession());
6017 EXPECT_EQ(minimized_window.get(), window_util::GetActiveWindow());
6018 }
6019
6020 // Verify no crash (or DCHECK failure) if you exit and re-enter mirror mode
6021 // while in tablet split view with empty overview.
TEST_P(SplitViewOverviewSessionTest,ExitAndReenterMirrorModeWithEmptyOverview)6022 TEST_P(SplitViewOverviewSessionTest,
6023 ExitAndReenterMirrorModeWithEmptyOverview) {
6024 UpdateDisplay("800x600,800x600");
6025 std::unique_ptr<aura::Window> window = CreateTestWindow();
6026 ToggleOverview();
6027 split_view_controller()->SnapWindow(window.get(), SplitViewController::LEFT);
6028 display_manager()->SetMirrorMode(display::MirrorMode::kOff, base::nullopt);
6029 display_manager()->SetMirrorMode(display::MirrorMode::kNormal, base::nullopt);
6030 }
6031
6032 // Test the split view and overview functionalities in clamshell mode. Split
6033 // view is only active when overview is active in clamshell mode.
6034 class SplitViewOverviewSessionInClamshellTest
6035 : public SplitViewOverviewSessionTest {
6036 public:
6037 SplitViewOverviewSessionInClamshellTest() = default;
6038 ~SplitViewOverviewSessionInClamshellTest() override = default;
6039
6040 // AshTestBase:
SetUp()6041 void SetUp() override {
6042 scoped_feature_list_.InitAndEnableFeature(
6043 features::kDragToSnapInClamshellMode);
6044 OverviewSessionTest::SetUp();
6045 Shell::Get()->tablet_mode_controller()->SetEnabledForTest(false);
6046 DCHECK(ShouldAllowSplitView());
6047 }
6048
CreateWindowWithHitTestComponent(int hit_test_component,const gfx::Rect & bounds)6049 aura::Window* CreateWindowWithHitTestComponent(int hit_test_component,
6050 const gfx::Rect& bounds) {
6051 return CreateTestWindowInShellWithDelegate(
6052 new TestWindowHitTestDelegate(hit_test_component), 0, bounds);
6053 }
6054
6055 private:
6056 class TestWindowHitTestDelegate : public aura::test::TestWindowDelegate {
6057 public:
TestWindowHitTestDelegate(int hit_test_component)6058 explicit TestWindowHitTestDelegate(int hit_test_component) {
6059 set_window_component(hit_test_component);
6060 }
6061 ~TestWindowHitTestDelegate() override = default;
6062
6063 private:
6064 // aura::Test::TestWindowDelegate:
OnWindowDestroyed(aura::Window * window)6065 void OnWindowDestroyed(aura::Window* window) override { delete this; }
6066
6067 DISALLOW_COPY_AND_ASSIGN(TestWindowHitTestDelegate);
6068 };
6069
6070 base::test::ScopedFeatureList scoped_feature_list_;
6071 DISALLOW_COPY_AND_ASSIGN(SplitViewOverviewSessionInClamshellTest);
6072 };
6073
6074 // Test some basic functionalities in clamshell splitview mode.
TEST_P(SplitViewOverviewSessionInClamshellTest,BasicFunctionalitiesTest)6075 TEST_P(SplitViewOverviewSessionInClamshellTest, BasicFunctionalitiesTest) {
6076 UpdateDisplay("600x400");
6077 EXPECT_FALSE(Shell::Get()->tablet_mode_controller()->InTabletMode());
6078
6079 // 1. Test the 1 window scenario.
6080 const gfx::Rect bounds(400, 400);
6081 std::unique_ptr<aura::Window> window1(CreateWindow(bounds));
6082 WindowState* window_state1 = WindowState::Get(window1.get());
6083 EXPECT_FALSE(window_state1->IsSnapped());
6084 ToggleOverview();
6085 EXPECT_TRUE(overview_controller()->InOverviewSession());
6086 EXPECT_FALSE(split_view_controller()->InSplitViewMode());
6087 // Drag |window1| selector item to snap to left.
6088 OverviewItem* overview_item1 = GetOverviewItemForWindow(window1.get());
6089 DragWindowTo(overview_item1, gfx::PointF(0, 0));
6090 // Since the only window is snapped, overview and splitview should be both
6091 // ended.
6092 EXPECT_EQ(window_state1->GetStateType(), WindowStateType::kLeftSnapped);
6093 EXPECT_FALSE(overview_controller()->InOverviewSession());
6094 EXPECT_FALSE(split_view_controller()->InSplitViewMode());
6095
6096 // 2. Test if one window is snapped, the other windows are showing in
6097 // overview, close all windows in overview will end overview and also
6098 // splitview.
6099 std::unique_ptr<aura::Window> window2(CreateWindow(bounds));
6100 ToggleOverview();
6101 EXPECT_TRUE(overview_controller()->InOverviewSession());
6102 EXPECT_FALSE(split_view_controller()->InSplitViewMode());
6103 overview_item1 = GetOverviewItemForWindow(window1.get());
6104 DragWindowTo(overview_item1, gfx::PointF(600, 300));
6105 // SplitView and overview are both active at the moment.
6106 EXPECT_TRUE(overview_controller()->InOverviewSession());
6107 EXPECT_TRUE(split_view_controller()->InSplitViewMode());
6108 EXPECT_TRUE(split_view_controller()->IsWindowInSplitView(window1.get()));
6109 EXPECT_TRUE(overview_controller()->overview_session()->IsWindowInOverview(
6110 window2.get()));
6111 EXPECT_EQ(window_state1->GetStateType(), WindowStateType::kRightSnapped);
6112 // Close |window2| will end overview and splitview.
6113 window2.reset();
6114 EXPECT_FALSE(overview_controller()->InOverviewSession());
6115 EXPECT_FALSE(split_view_controller()->InSplitViewMode());
6116
6117 // 3. Test that snap 2 windows will end overview and splitview.
6118 std::unique_ptr<aura::Window> window3(CreateWindow(bounds));
6119 ToggleOverview();
6120 overview_item1 = GetOverviewItemForWindow(window1.get());
6121 DragWindowTo(overview_item1, gfx::PointF(0, 0));
6122 OverviewItem* overview_item3 = GetOverviewItemForWindow(window3.get());
6123 DragWindowTo(overview_item3, gfx::PointF(600, 300));
6124 EXPECT_EQ(window_state1->GetStateType(), WindowStateType::kLeftSnapped);
6125 EXPECT_EQ(WindowState::Get(window3.get())->GetStateType(),
6126 WindowStateType::kRightSnapped);
6127 EXPECT_FALSE(overview_controller()->InOverviewSession());
6128 EXPECT_FALSE(split_view_controller()->InSplitViewMode());
6129
6130 // 4. Test if one window is snapped, the other windows are showing in
6131 // overview, we can drag another window in overview to snap in splitview, and
6132 // the previous snapped window will be put back into overview.
6133 std::unique_ptr<aura::Window> window4(CreateWindow(bounds));
6134 ToggleOverview();
6135 overview_item1 = GetOverviewItemForWindow(window1.get());
6136 DragWindowTo(overview_item1, gfx::PointF(0, 0));
6137 EXPECT_FALSE(overview_controller()->overview_session()->IsWindowInOverview(
6138 window1.get()));
6139 overview_item3 = GetOverviewItemForWindow(window3.get());
6140 DragWindowTo(overview_item3, gfx::PointF(0, 0));
6141 EXPECT_FALSE(overview_controller()->overview_session()->IsWindowInOverview(
6142 window3.get()));
6143 EXPECT_TRUE(overview_controller()->overview_session()->IsWindowInOverview(
6144 window1.get()));
6145 EXPECT_EQ(window_state1->GetStateType(), WindowStateType::kLeftSnapped);
6146 EXPECT_EQ(WindowState::Get(window3.get())->GetStateType(),
6147 WindowStateType::kLeftSnapped);
6148 EXPECT_TRUE(overview_controller()->InOverviewSession());
6149 EXPECT_TRUE(split_view_controller()->InSplitViewMode());
6150 // End overview, test that we'll not auto-snap a window to the right side of
6151 // the screen.
6152 EXPECT_EQ(WindowState::Get(window4.get())->GetStateType(),
6153 WindowStateType::kDefault);
6154 ToggleOverview();
6155 EXPECT_EQ(WindowState::Get(window4.get())->GetStateType(),
6156 WindowStateType::kDefault);
6157 EXPECT_FALSE(overview_controller()->InOverviewSession());
6158 EXPECT_FALSE(split_view_controller()->InSplitViewMode());
6159
6160 // 5. Test if one window is snapped, the other window are showing in overview,
6161 // activating an new window will not auto-snap the new window. Overview and
6162 // splitview should be ended.
6163 ToggleOverview();
6164 overview_item1 = GetOverviewItemForWindow(window1.get());
6165 DragWindowTo(overview_item1, gfx::PointF(0, 0));
6166 EXPECT_TRUE(overview_controller()->InOverviewSession());
6167 EXPECT_TRUE(split_view_controller()->InSplitViewMode());
6168 std::unique_ptr<aura::Window> window5(CreateWindow(bounds));
6169 EXPECT_EQ(WindowState::Get(window5.get())->GetStateType(),
6170 WindowStateType::kDefault);
6171 wm::ActivateWindow(window5.get());
6172 EXPECT_EQ(WindowState::Get(window5.get())->GetStateType(),
6173 WindowStateType::kDefault);
6174 EXPECT_FALSE(overview_controller()->InOverviewSession());
6175 EXPECT_FALSE(split_view_controller()->InSplitViewMode());
6176
6177 // 6. Test if one window is snapped, the other window is showing in overview,
6178 // close the snapped window will end split view, but overview is still active.
6179 ToggleOverview();
6180 const gfx::Rect overview_bounds = GetGridBounds();
6181 overview_item1 = GetOverviewItemForWindow(window1.get());
6182 DragWindowTo(overview_item1, gfx::PointF(0, 0));
6183 EXPECT_TRUE(overview_controller()->InOverviewSession());
6184 EXPECT_TRUE(split_view_controller()->InSplitViewMode());
6185 EXPECT_NE(GetGridBounds(), overview_bounds);
6186 EXPECT_EQ(GetGridBounds(), GetSplitViewRightWindowBounds());
6187 window1.reset();
6188 EXPECT_TRUE(overview_controller()->InOverviewSession());
6189 EXPECT_FALSE(split_view_controller()->InSplitViewMode());
6190 // Overview bounds will adjust from snapped bounds to fullscreen bounds.
6191 EXPECT_EQ(GetGridBounds(), overview_bounds);
6192
6193 // 7. Test if split view mode is active, open the app list will end both
6194 // overview and splitview.
6195 overview_item3 = GetOverviewItemForWindow(window3.get());
6196 DragWindowTo(overview_item3, gfx::PointF(0, 0));
6197 EXPECT_TRUE(overview_controller()->InOverviewSession());
6198 EXPECT_TRUE(split_view_controller()->InSplitViewMode());
6199 // Open app list.
6200 AppListControllerImpl* app_list_controller =
6201 Shell::Get()->app_list_controller();
6202 app_list_controller->ToggleAppList(
6203 display::Screen::GetScreen()->GetDisplayNearestWindow(window3.get()).id(),
6204 AppListShowSource::kSearchKey, base::TimeTicks());
6205 base::RunLoop().RunUntilIdle();
6206 EXPECT_FALSE(overview_controller()->InOverviewSession());
6207 EXPECT_FALSE(split_view_controller()->InSplitViewMode());
6208
6209 // 8. Test if splitview is not active, open the app list will end overview if
6210 // overview is active.
6211 ToggleOverview();
6212 // Open app list.
6213 app_list_controller->ToggleAppList(
6214 display::Screen::GetScreen()->GetDisplayNearestWindow(window3.get()).id(),
6215 AppListShowSource::kSearchKey, base::TimeTicks());
6216 base::RunLoop().RunUntilIdle();
6217 EXPECT_FALSE(overview_controller()->InOverviewSession());
6218 EXPECT_FALSE(split_view_controller()->InSplitViewMode());
6219 }
6220
6221 // Test overview exit animation histograms when you drag to snap two windows on
6222 // opposite sides.
TEST_P(SplitViewOverviewSessionInClamshellTest,BothSnappedOverviewExitAnimationHistogramTest)6223 TEST_P(SplitViewOverviewSessionInClamshellTest,
6224 BothSnappedOverviewExitAnimationHistogramTest) {
6225 ui::ScopedAnimationDurationScaleMode anmatin_scale(
6226 ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
6227 const gfx::Rect bounds(400, 400);
6228 std::unique_ptr<aura::Window> left_window(CreateWindow(bounds));
6229 std::unique_ptr<aura::Window> right_window(CreateWindow(bounds));
6230 CheckOverviewEnterExitHistogram("Init", {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0});
6231
6232 ToggleOverview();
6233 WaitForOverviewEnterAnimation();
6234 CheckOverviewEnterExitHistogram("EnterOverview", {1, 0, 0, 0, 0},
6235 {0, 0, 0, 0, 0});
6236
6237 DragWindowTo(GetOverviewItemForWindow(left_window.get()), gfx::PointF(0, 0));
6238 DragWindowTo(GetOverviewItemForWindow(right_window.get()),
6239 gfx::PointF(799, 300));
6240 WaitForOverviewExitAnimation();
6241 CheckOverviewEnterExitHistogram("SnapBothSides", {1, 0, 0, 0, 0},
6242 {1, 0, 0, 0, 1});
6243 }
6244
6245 // Test that when overview and splitview are both active, only resize that
6246 // happens on eligible window components will change snapped window bounds and
6247 // overview bounds at the same time.
TEST_P(SplitViewOverviewSessionInClamshellTest,ResizeWindowTest)6248 TEST_P(SplitViewOverviewSessionInClamshellTest, ResizeWindowTest) {
6249 UpdateDisplay("600x400");
6250 const gfx::Rect bounds(400, 400);
6251 std::unique_ptr<aura::Window> window1(
6252 CreateWindowWithHitTestComponent(HTRIGHT, bounds));
6253 std::unique_ptr<aura::Window> window2(
6254 CreateWindowWithHitTestComponent(HTLEFT, bounds));
6255 std::unique_ptr<aura::Window> window3(
6256 CreateWindowWithHitTestComponent(HTTOP, bounds));
6257 std::unique_ptr<aura::Window> window4(
6258 CreateWindowWithHitTestComponent(HTBOTTOM, bounds));
6259
6260 ToggleOverview();
6261 gfx::Rect overview_full_bounds = GetGridBounds();
6262 OverviewItem* overview_item1 = GetOverviewItemForWindow(window1.get());
6263 DragWindowTo(overview_item1, gfx::PointF(0, 0));
6264 EXPECT_NE(GetGridBounds(), overview_full_bounds);
6265 EXPECT_EQ(GetGridBounds(), GetSplitViewRightWindowBounds());
6266 gfx::Rect overview_snapped_bounds = GetGridBounds();
6267
6268 // Resize that happens on the right edge of the left snapped window will
6269 // resize the window and overview at the same time.
6270 ui::test::EventGenerator generator1(Shell::GetPrimaryRootWindow(),
6271 window1.get());
6272 generator1.PressLeftButton();
6273 CheckWindowResizingPerformanceHistograms("BeforeResizingLeftSnappedWindow1",
6274 0, 0, 0, 0);
6275 generator1.MoveMouseBy(50, 50);
6276 CheckWindowResizingPerformanceHistograms("WhileResizingLeftSnappedWindow1", 0,
6277 0, 1, 0);
6278 generator1.ReleaseLeftButton();
6279 CheckWindowResizingPerformanceHistograms("AfterResizingLeftSnappedWindow1", 0,
6280 0, 1, 1);
6281 EXPECT_TRUE(overview_controller()->InOverviewSession());
6282 EXPECT_TRUE(split_view_controller()->InSplitViewMode());
6283 EXPECT_NE(GetGridBounds(), overview_full_bounds);
6284 EXPECT_NE(GetGridBounds(), overview_snapped_bounds);
6285 EXPECT_EQ(GetGridBounds(), GetSplitViewRightWindowBounds());
6286
6287 // Resize that happens on the left edge of the left snapped window will end
6288 // overview. The same for the resize that happens on the top or bottom edge of
6289 // the left snapped window.
6290 OverviewItem* overview_item2 = GetOverviewItemForWindow(window2.get());
6291 DragWindowTo(overview_item2, gfx::PointF(0, 0));
6292 EXPECT_TRUE(overview_controller()->InOverviewSession());
6293 EXPECT_TRUE(split_view_controller()->InSplitViewMode());
6294 ui::test::EventGenerator generator2(Shell::GetPrimaryRootWindow(),
6295 window2.get());
6296 generator2.DragMouseBy(50, 50);
6297 CheckWindowResizingPerformanceHistograms("AfterResizingLeftSnappedWindow2", 0,
6298 0, 1, 1);
6299 EXPECT_FALSE(overview_controller()->InOverviewSession());
6300 EXPECT_FALSE(split_view_controller()->InSplitViewMode());
6301
6302 ToggleOverview();
6303 OverviewItem* overview_item3 = GetOverviewItemForWindow(window3.get());
6304 DragWindowTo(overview_item3, gfx::PointF(0, 0));
6305 ui::test::EventGenerator generator3(Shell::GetPrimaryRootWindow(),
6306 window3.get());
6307 generator3.DragMouseBy(50, 50);
6308 CheckWindowResizingPerformanceHistograms("AfterResizingLeftSnappedWindow3", 0,
6309 0, 1, 1);
6310 EXPECT_FALSE(overview_controller()->InOverviewSession());
6311 EXPECT_FALSE(split_view_controller()->InSplitViewMode());
6312
6313 ToggleOverview();
6314 OverviewItem* overview_item4 = GetOverviewItemForWindow(window4.get());
6315 DragWindowTo(overview_item4, gfx::PointF(0, 0));
6316 ui::test::EventGenerator generator4(Shell::GetPrimaryRootWindow(),
6317 window4.get());
6318 generator4.DragMouseBy(50, 50);
6319 CheckWindowResizingPerformanceHistograms("AfterResizingLeftSnappedWindow4", 0,
6320 0, 1, 1);
6321 EXPECT_FALSE(overview_controller()->InOverviewSession());
6322 EXPECT_FALSE(split_view_controller()->InSplitViewMode());
6323
6324 // Now try snapping on the right.
6325 ToggleOverview();
6326 overview_full_bounds = GetGridBounds();
6327 overview_item2 = GetOverviewItemForWindow(window2.get());
6328 DragWindowTo(overview_item2, gfx::PointF(599, 0));
6329 EXPECT_NE(GetGridBounds(), overview_full_bounds);
6330 EXPECT_EQ(GetGridBounds(), GetSplitViewLeftWindowBounds());
6331 overview_snapped_bounds = GetGridBounds();
6332
6333 ui::test::EventGenerator generator5(Shell::GetPrimaryRootWindow(),
6334 window2.get());
6335 generator5.PressLeftButton();
6336 CheckWindowResizingPerformanceHistograms("BeforeResizingRightSnappedWindow2",
6337 0, 0, 1, 1);
6338 generator5.MoveMouseBy(50, 50);
6339 CheckWindowResizingPerformanceHistograms("WhileResizingRightSnappedWindow2",
6340 0, 0, 2, 1);
6341 generator5.ReleaseLeftButton();
6342 CheckWindowResizingPerformanceHistograms("AfterResizingRightSnappedWindow2",
6343 0, 0, 2, 2);
6344 EXPECT_TRUE(overview_controller()->InOverviewSession());
6345 EXPECT_TRUE(split_view_controller()->InSplitViewMode());
6346 EXPECT_NE(GetGridBounds(), overview_full_bounds);
6347 EXPECT_NE(GetGridBounds(), overview_snapped_bounds);
6348 EXPECT_EQ(GetGridBounds(), GetSplitViewLeftWindowBounds());
6349
6350 overview_item1 = GetOverviewItemForWindow(window1.get());
6351 DragWindowTo(overview_item1, gfx::PointF(599, 0));
6352 EXPECT_TRUE(overview_controller()->InOverviewSession());
6353 EXPECT_TRUE(split_view_controller()->InSplitViewMode());
6354 ui::test::EventGenerator generator6(Shell::GetPrimaryRootWindow(),
6355 window1.get());
6356 generator6.DragMouseBy(50, 50);
6357 CheckWindowResizingPerformanceHistograms("AfterResizingRightSnappedWindow1",
6358 0, 0, 2, 2);
6359 EXPECT_FALSE(overview_controller()->InOverviewSession());
6360 EXPECT_FALSE(split_view_controller()->InSplitViewMode());
6361
6362 ToggleOverview();
6363 overview_item3 = GetOverviewItemForWindow(window3.get());
6364 DragWindowTo(overview_item3, gfx::PointF(599, 0));
6365 ui::test::EventGenerator generator7(Shell::GetPrimaryRootWindow(),
6366 window3.get());
6367 generator7.DragMouseBy(50, 50);
6368 CheckWindowResizingPerformanceHistograms("AfterResizingRightSnappedWindow3",
6369 0, 0, 2, 2);
6370 EXPECT_FALSE(overview_controller()->InOverviewSession());
6371 EXPECT_FALSE(split_view_controller()->InSplitViewMode());
6372
6373 ToggleOverview();
6374 overview_item4 = GetOverviewItemForWindow(window4.get());
6375 DragWindowTo(overview_item4, gfx::PointF(599, 0));
6376 ui::test::EventGenerator generator8(Shell::GetPrimaryRootWindow(),
6377 window4.get());
6378 generator8.DragMouseBy(50, 50);
6379 CheckWindowResizingPerformanceHistograms("AfterResizingRightSnappedWindow4",
6380 0, 0, 2, 2);
6381 EXPECT_FALSE(overview_controller()->InOverviewSession());
6382 EXPECT_FALSE(split_view_controller()->InSplitViewMode());
6383 }
6384
6385 // Test closing the split view window while resizing it.
TEST_P(SplitViewOverviewSessionInClamshellTest,CloseWindowWhileResizingItTest)6386 TEST_P(SplitViewOverviewSessionInClamshellTest,
6387 CloseWindowWhileResizingItTest) {
6388 UpdateDisplay("600x400");
6389 const gfx::Rect bounds(400, 400);
6390 std::unique_ptr<aura::Window> split_view_window(
6391 CreateWindowWithHitTestComponent(HTRIGHT, bounds));
6392 std::unique_ptr<aura::Window> overview_window(CreateWindow(bounds));
6393 ToggleOverview();
6394 DragWindowTo(GetOverviewItemForWindow(split_view_window.get()),
6395 gfx::PointF(0.f, 0.f));
6396 EXPECT_TRUE(overview_controller()->InOverviewSession());
6397 EXPECT_TRUE(split_view_controller()->InSplitViewMode());
6398 ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
6399 split_view_window.get());
6400 generator.PressLeftButton();
6401 CheckWindowResizingPerformanceHistograms("AfterPressingMouseButton", 0, 0, 0,
6402 0);
6403 generator.MoveMouseBy(50, 50);
6404 CheckWindowResizingPerformanceHistograms("WhileResizing", 0, 0, 1, 0);
6405 split_view_window.reset();
6406 CheckWindowResizingPerformanceHistograms("AfterClosing", 0, 0, 1, 1);
6407 EXPECT_TRUE(overview_controller()->InOverviewSession());
6408 EXPECT_FALSE(split_view_controller()->InSplitViewMode());
6409 generator.ReleaseLeftButton();
6410 CheckWindowResizingPerformanceHistograms("AfterReleasingMouseButton", 0, 0, 1,
6411 1);
6412 EXPECT_TRUE(overview_controller()->InOverviewSession());
6413 EXPECT_FALSE(split_view_controller()->InSplitViewMode());
6414 }
6415
6416 class TestWindowStateDelegate : public WindowStateDelegate {
6417 public:
6418 TestWindowStateDelegate() = default;
6419 TestWindowStateDelegate(const TestWindowStateDelegate&) = delete;
6420 TestWindowStateDelegate& operator=(const TestWindowStateDelegate&) = delete;
6421 ~TestWindowStateDelegate() override = default;
6422
6423 // WindowStateDelegate:
OnDragStarted(int component)6424 void OnDragStarted(int component) override { drag_in_progress_ = true; }
OnDragFinished(bool cancel,const gfx::PointF & location)6425 void OnDragFinished(bool cancel, const gfx::PointF& location) override {
6426 drag_in_progress_ = false;
6427 }
6428
drag_in_progress()6429 bool drag_in_progress() { return drag_in_progress_; }
6430
6431 private:
6432 bool drag_in_progress_ = false;
6433 };
6434
6435 // Tests that when a split view window carries over to clamshell split view
6436 // while the divider is being dragged, the window resize is properly completed.
TEST_P(SplitViewOverviewSessionInClamshellTest,CarryOverToClamshellSplitViewWhileResizing)6437 TEST_P(SplitViewOverviewSessionInClamshellTest,
6438 CarryOverToClamshellSplitViewWhileResizing) {
6439 std::unique_ptr<aura::Window> snapped_window = CreateTestWindow();
6440 std::unique_ptr<aura::Window> overview_window = CreateTestWindow();
6441 WindowState* snapped_window_state = WindowState::Get(snapped_window.get());
6442 TestWindowStateDelegate* snapped_window_state_delegate =
6443 new TestWindowStateDelegate();
6444 snapped_window_state->SetDelegate(
6445 base::WrapUnique(snapped_window_state_delegate));
6446
6447 // Enter clamshell split view and then switch to tablet mode.
6448 ToggleOverview();
6449 split_view_controller()->SnapWindow(snapped_window.get(),
6450 SplitViewController::LEFT);
6451 EnterTabletMode();
6452 ASSERT_EQ(SplitViewController::State::kLeftSnapped,
6453 split_view_controller()->state());
6454 ASSERT_EQ(snapped_window.get(), split_view_controller()->left_window());
6455
6456 // Start dragging the divider.
6457 ui::test::EventGenerator* generator = GetEventGenerator();
6458 generator->set_current_screen_location(
6459 split_view_controller()
6460 ->split_view_divider()
6461 ->GetDividerBoundsInScreen(/*is_dragging=*/false)
6462 .CenterPoint());
6463 generator->PressTouch();
6464 generator->MoveTouchBy(5, 0);
6465 EXPECT_TRUE(snapped_window_state_delegate->drag_in_progress());
6466 EXPECT_NE(nullptr, snapped_window_state->drag_details());
6467
6468 // End tablet mode.
6469 Shell::Get()->tablet_mode_controller()->SetEnabledForTest(false);
6470 ASSERT_EQ(SplitViewController::State::kLeftSnapped,
6471 split_view_controller()->state());
6472 ASSERT_EQ(snapped_window.get(), split_view_controller()->left_window());
6473 EXPECT_FALSE(snapped_window_state_delegate->drag_in_progress());
6474 EXPECT_EQ(nullptr, snapped_window_state->drag_details());
6475 }
6476
6477 // Test that overview and clamshell split view end if you double click the edge
6478 // of the split view window where it meets the overview grid.
TEST_P(SplitViewOverviewSessionInClamshellTest,HorizontalMaximizeTest)6479 TEST_P(SplitViewOverviewSessionInClamshellTest, HorizontalMaximizeTest) {
6480 const gfx::Rect bounds(400, 400);
6481 std::unique_ptr<aura::Window> snapped_window(
6482 CreateWindowWithHitTestComponent(HTRIGHT, bounds));
6483 std::unique_ptr<aura::Window> overview_window = CreateTestWindow(bounds);
6484 ToggleOverview();
6485 split_view_controller()->SnapWindow(snapped_window.get(),
6486 SplitViewController::LEFT);
6487 EXPECT_TRUE(overview_controller()->InOverviewSession());
6488 EXPECT_TRUE(split_view_controller()->InSplitViewMode());
6489 ui::test::EventGenerator(Shell::GetPrimaryRootWindow(), snapped_window.get())
6490 .DoubleClickLeftButton();
6491 EXPECT_FALSE(overview_controller()->InOverviewSession());
6492 EXPECT_FALSE(split_view_controller()->InSplitViewMode());
6493 }
6494
6495 // Test that when laptop splitview mode is active, moving the snapped window
6496 // will end splitview and overview at the same time.
TEST_P(SplitViewOverviewSessionInClamshellTest,MoveWindowTest)6497 TEST_P(SplitViewOverviewSessionInClamshellTest, MoveWindowTest) {
6498 const gfx::Rect bounds(400, 400);
6499 std::unique_ptr<aura::Window> window1(
6500 CreateWindowWithHitTestComponent(HTCAPTION, bounds));
6501 std::unique_ptr<aura::Window> window2(
6502 CreateWindowWithHitTestComponent(HTCAPTION, bounds));
6503
6504 ToggleOverview();
6505 OverviewItem* overview_item1 = GetOverviewItemForWindow(window1.get());
6506 DragWindowTo(overview_item1, gfx::PointF(0, 0));
6507 EXPECT_TRUE(overview_controller()->InOverviewSession());
6508 EXPECT_TRUE(split_view_controller()->InSplitViewMode());
6509
6510 ui::test::EventGenerator generator1(Shell::GetPrimaryRootWindow(),
6511 window1.get());
6512 generator1.DragMouseBy(50, 50);
6513 EXPECT_FALSE(overview_controller()->InOverviewSession());
6514 EXPECT_FALSE(split_view_controller()->InSplitViewMode());
6515 }
6516
6517 // Test that in clamshell splitview mode, if the snapped window is minimized,
6518 // splitview mode and overview mode are both ended.
TEST_P(SplitViewOverviewSessionInClamshellTest,MinimizedWindowTest)6519 TEST_P(SplitViewOverviewSessionInClamshellTest, MinimizedWindowTest) {
6520 const gfx::Rect bounds(400, 400);
6521 std::unique_ptr<aura::Window> window1(CreateWindow(bounds));
6522 std::unique_ptr<aura::Window> window2(CreateWindow(bounds));
6523
6524 ToggleOverview();
6525 // Drag |window1| selector item to snap to left.
6526 OverviewItem* overview_item1 = GetOverviewItemForWindow(window1.get());
6527 DragWindowTo(overview_item1, gfx::PointF(0, 0));
6528 EXPECT_TRUE(overview_controller()->InOverviewSession());
6529 EXPECT_TRUE(split_view_controller()->InSplitViewMode());
6530
6531 // Now minimize the snapped |window1|.
6532 WindowState::Get(window1.get())->Minimize();
6533 EXPECT_FALSE(overview_controller()->InOverviewSession());
6534 EXPECT_FALSE(split_view_controller()->InSplitViewMode());
6535 }
6536
6537 // Test snapped window bounds with adjustment for the minimum size of a window.
TEST_P(SplitViewOverviewSessionInClamshellTest,SnappedWindowBoundsWithMinimumSizeTest)6538 TEST_P(SplitViewOverviewSessionInClamshellTest,
6539 SnappedWindowBoundsWithMinimumSizeTest) {
6540 const gfx::Rect bounds(400, 400);
6541 std::unique_ptr<aura::Window> window1(
6542 CreateWindowWithHitTestComponent(HTRIGHT, bounds));
6543 const int window2_minimum_size = 350;
6544 std::unique_ptr<aura::Window> window2(
6545 CreateWindowWithMinimumSize(bounds, gfx::Size(window2_minimum_size, 0)));
6546
6547 ToggleOverview();
6548 split_view_controller()->SnapWindow(window1.get(), SplitViewController::LEFT);
6549 ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
6550 window1.get());
6551 int divider_position = split_view_controller()->divider_position();
6552 generator.MoveMouseTo(divider_position, 10);
6553 divider_position = 300;
6554 generator.DragMouseTo(divider_position, 10);
6555 EXPECT_EQ(divider_position, split_view_controller()
6556 ->GetSnappedWindowBoundsInScreen(
6557 SplitViewController::LEFT,
6558 /*window_for_minimum_size=*/nullptr)
6559 .width());
6560 EXPECT_EQ(window2_minimum_size,
6561 split_view_controller()
6562 ->GetSnappedWindowBoundsInScreen(SplitViewController::LEFT,
6563 window2.get())
6564 .width());
6565 const int work_area_length =
6566 screen_util::GetDisplayWorkAreaBoundsInScreenForActiveDeskContainer(
6567 window1.get())
6568 .width();
6569 EXPECT_EQ(
6570 work_area_length - divider_position,
6571 split_view_controller()
6572 ->GetSnappedWindowBoundsInScreen(SplitViewController::RIGHT,
6573 /*window_for_minimum_size=*/nullptr)
6574 .width());
6575 EXPECT_EQ(work_area_length - divider_position,
6576 split_view_controller()
6577 ->GetSnappedWindowBoundsInScreen(SplitViewController::RIGHT,
6578 window2.get())
6579 .width());
6580 divider_position = 500;
6581 generator.DragMouseTo(divider_position, 10);
6582 EXPECT_EQ(divider_position, split_view_controller()
6583 ->GetSnappedWindowBoundsInScreen(
6584 SplitViewController::LEFT,
6585 /*window_for_minimum_size=*/nullptr)
6586 .width());
6587 EXPECT_EQ(divider_position, split_view_controller()
6588 ->GetSnappedWindowBoundsInScreen(
6589 SplitViewController::LEFT, window2.get())
6590 .width());
6591 EXPECT_EQ(
6592 work_area_length - divider_position,
6593 split_view_controller()
6594 ->GetSnappedWindowBoundsInScreen(SplitViewController::RIGHT,
6595 /*window_for_minimum_size=*/nullptr)
6596 .width());
6597 EXPECT_EQ(window2_minimum_size,
6598 split_view_controller()
6599 ->GetSnappedWindowBoundsInScreen(SplitViewController::RIGHT,
6600 window2.get())
6601 .width());
6602 }
6603
6604 // Tests that on a display in portrait orientation, clamshell split view still
6605 // uses snap positions on the left and right.
TEST_P(SplitViewOverviewSessionInClamshellTest,PortraitClamshellSplitViewSnapPositionsTest)6606 TEST_P(SplitViewOverviewSessionInClamshellTest,
6607 PortraitClamshellSplitViewSnapPositionsTest) {
6608 UpdateDisplay("800x600/l");
6609 const int height = 800 - ShelfConfig::Get()->shelf_size();
6610 ASSERT_EQ(gfx::Rect(0, 0, 600, height),
6611 screen_util::GetDisplayWorkAreaBoundsInScreenForActiveDeskContainer(
6612 Shell::GetPrimaryRootWindow()));
6613 // Check that snapped window bounds represent snapping on the left and right.
6614 const gfx::Rect left_snapped_bounds(0, 0, 300, height);
6615 EXPECT_EQ(
6616 left_snapped_bounds,
6617 split_view_controller()->GetSnappedWindowBoundsInScreen(
6618 SplitViewController::LEFT, /*window_for_minimum_size=*/nullptr));
6619 const gfx::Rect right_snapped_bounds(300, 0, 300, height);
6620 EXPECT_EQ(
6621 right_snapped_bounds,
6622 split_view_controller()->GetSnappedWindowBoundsInScreen(
6623 SplitViewController::RIGHT, /*window_for_minimum_size=*/nullptr));
6624 // Switch from clamshell mode to tablet mode and then back to clamshell mode.
6625 display::test::DisplayManagerTestApi(Shell::Get()->display_manager())
6626 .SetFirstDisplayAsInternalDisplay();
6627 TabletModeControllerTestApi tablet_mode_controller_test_api;
6628 tablet_mode_controller_test_api.DetachAllMice();
6629 EXPECT_FALSE(tablet_mode_controller_test_api.IsTabletModeStarted());
6630 tablet_mode_controller_test_api.OpenLidToAngle(315.0f);
6631 EXPECT_TRUE(tablet_mode_controller_test_api.IsTabletModeStarted());
6632 tablet_mode_controller_test_api.OpenLidToAngle(90.0f);
6633 EXPECT_FALSE(tablet_mode_controller_test_api.IsTabletModeStarted());
6634 // Check the snapped window bounds again. They should be the same as before.
6635 EXPECT_EQ(
6636 left_snapped_bounds,
6637 split_view_controller()->GetSnappedWindowBoundsInScreen(
6638 SplitViewController::LEFT, /*window_for_minimum_size=*/nullptr));
6639 EXPECT_EQ(
6640 right_snapped_bounds,
6641 split_view_controller()->GetSnappedWindowBoundsInScreen(
6642 SplitViewController::RIGHT, /*window_for_minimum_size=*/nullptr));
6643 }
6644
6645 // Tests that the ratio between the divider position and the work area width is
6646 // the same before and after changing the display orientation in clamshell mode.
TEST_P(SplitViewOverviewSessionInClamshellTest,DisplayOrientationChangeTest)6647 TEST_P(SplitViewOverviewSessionInClamshellTest, DisplayOrientationChangeTest) {
6648 UpdateDisplay("600x400");
6649 const gfx::Rect bounds(400, 400);
6650 std::unique_ptr<aura::Window> split_view_window(
6651 CreateWindowWithHitTestComponent(HTRIGHT, bounds));
6652 std::unique_ptr<aura::Window> overview_window(CreateWindow(bounds));
6653 ToggleOverview();
6654 split_view_controller()->SnapWindow(split_view_window.get(),
6655 SplitViewController::LEFT);
6656 const auto test_many_orientation_changes =
6657 [this](const std::string& description) {
6658 SCOPED_TRACE(description);
6659 for (display::Display::Rotation rotation :
6660 {display::Display::ROTATE_270, display::Display::ROTATE_180,
6661 display::Display::ROTATE_90, display::Display::ROTATE_0,
6662 display::Display::ROTATE_180, display::Display::ROTATE_0}) {
6663 const auto compute_divider_position_ratio = [this]() {
6664 return static_cast<float>(
6665 split_view_controller()->divider_position()) /
6666 static_cast<float>(display::Screen::GetScreen()
6667 ->GetPrimaryDisplay()
6668 .work_area()
6669 .width());
6670 };
6671 const float before = compute_divider_position_ratio();
6672 Shell::Get()->display_manager()->SetDisplayRotation(
6673 display::Screen::GetScreen()->GetPrimaryDisplay().id(), rotation,
6674 display::Display::RotationSource::ACTIVE);
6675 const float after = compute_divider_position_ratio();
6676 EXPECT_NEAR(before, after, 0.001f);
6677 }
6678 };
6679 EXPECT_EQ(split_view_controller()->GetDefaultDividerPosition(),
6680 split_view_controller()->divider_position());
6681 test_many_orientation_changes("centered divider");
6682 EXPECT_EQ(split_view_controller()->GetDefaultDividerPosition(),
6683 split_view_controller()->divider_position());
6684 ui::test::EventGenerator(Shell::GetPrimaryRootWindow(),
6685 split_view_window.get())
6686 .DragMouseBy(50, 50);
6687 EXPECT_NE(split_view_controller()->GetDefaultDividerPosition(),
6688 split_view_controller()->divider_position());
6689 test_many_orientation_changes("off-center divider");
6690 }
6691
6692 // Verify that an item's unsnappable indicator is updated for display rotation.
TEST_P(SplitViewOverviewSessionInClamshellTest,OverviewUnsnappableIndicatorVisibilityAfterDisplayRotation)6693 TEST_P(SplitViewOverviewSessionInClamshellTest,
6694 OverviewUnsnappableIndicatorVisibilityAfterDisplayRotation) {
6695 UpdateDisplay("900x600");
6696 std::unique_ptr<aura::Window> snapped_window = CreateTestWindow();
6697 // Because of its minimum size, |overview_window| is snappable in clamshell
6698 // split view with landscape display orientation but not with portrait display
6699 // orientation.
6700 std::unique_ptr<aura::Window> overview_window(
6701 CreateWindowWithMinimumSize(gfx::Rect(400, 400), gfx::Size(400, 0)));
6702 ToggleOverview();
6703 ASSERT_TRUE(overview_controller()->InOverviewSession());
6704 split_view_controller()->SnapWindow(snapped_window.get(),
6705 SplitViewController::LEFT);
6706 ASSERT_TRUE(split_view_controller()->InSplitViewMode());
6707 OverviewItem* overview_item = GetOverviewItemForWindow(overview_window.get());
6708 // Note: |cannot_snap_label_view_| and its parent will be created on demand.
6709 EXPECT_FALSE(overview_item->cannot_snap_widget_for_testing());
6710
6711 // Rotate to primary portrait orientation. The unsnappable indicator appears.
6712 display::DisplayManager* display_manager = Shell::Get()->display_manager();
6713 const int64_t display_id =
6714 display::Screen::GetScreen()->GetPrimaryDisplay().id();
6715 display_manager->SetDisplayRotation(display_id, display::Display::ROTATE_270,
6716 display::Display::RotationSource::ACTIVE);
6717 ASSERT_TRUE(overview_item->cannot_snap_widget_for_testing());
6718 ui::Layer* unsnappable_layer =
6719 overview_item->cannot_snap_widget_for_testing()->GetLayer();
6720 EXPECT_EQ(1.f, unsnappable_layer->opacity());
6721
6722 // Rotate to primary landscape orientation. The unsnappable indicator hides.
6723 display_manager->SetDisplayRotation(display_id, display::Display::ROTATE_0,
6724 display::Display::RotationSource::ACTIVE);
6725 EXPECT_EQ(0.f, unsnappable_layer->opacity());
6726 }
6727
6728 // Tests that dragging a window from overview creates a drop target on the same
6729 // display, even if the window bounds are mostly on another display.
TEST_P(SplitViewOverviewSessionInClamshellTest,DragFromOverviewWithBoundsMostlyOnAnotherDisplay)6730 TEST_P(SplitViewOverviewSessionInClamshellTest,
6731 DragFromOverviewWithBoundsMostlyOnAnotherDisplay) {
6732 UpdateDisplay("600x600,600x600");
6733 const aura::Window::Windows root_windows = Shell::Get()->GetAllRootWindows();
6734 ASSERT_EQ(2u, root_windows.size());
6735 const display::DisplayIdList display_ids =
6736 display_manager()->GetCurrentDisplayIdList();
6737 ASSERT_EQ(2u, display_ids.size());
6738 ASSERT_EQ(root_windows[0], Shell::GetRootWindowForDisplayId(display_ids[0]));
6739 ASSERT_EQ(root_windows[1], Shell::GetRootWindowForDisplayId(display_ids[1]));
6740
6741 display::Screen* screen = display::Screen::GetScreen();
6742 const gfx::Rect creation_bounds(0, 0, 600, 600);
6743 ASSERT_EQ(display_ids[0], screen->GetDisplayMatching(creation_bounds).id());
6744 const gfx::Rect bounds(550, 0, 600, 600);
6745 ASSERT_EQ(display_ids[1], screen->GetDisplayMatching(bounds).id());
6746 std::unique_ptr<aura::Window> window = CreateTestWindow(creation_bounds);
6747 window->SetBoundsInScreen(bounds,
6748 display_manager()->GetDisplayForId(display_ids[0]));
6749
6750 ToggleOverview();
6751 OverviewItem* overview_item = GetOverviewItemForWindow(window.get());
6752 EXPECT_FALSE(GetDropTarget(0));
6753 EXPECT_FALSE(GetDropTarget(1));
6754 gfx::PointF drag_point = overview_item->target_bounds().CenterPoint();
6755 overview_session()->InitiateDrag(overview_item, drag_point,
6756 /*is_touch_dragging=*/false);
6757 EXPECT_FALSE(GetDropTarget(0));
6758 EXPECT_FALSE(GetDropTarget(1));
6759 drag_point.Offset(5.f, 0.f);
6760 overview_session()->Drag(overview_item, drag_point);
6761 EXPECT_FALSE(GetDropTarget(1));
6762 ASSERT_TRUE(GetDropTarget(0));
6763 EXPECT_EQ(root_windows[0], GetDropTarget(0)->root_window());
6764 overview_session()->CompleteDrag(overview_item, drag_point);
6765 EXPECT_FALSE(GetDropTarget(0));
6766 EXPECT_FALSE(GetDropTarget(1));
6767 }
6768
6769 // Tests that Alt+[ and Alt+] do not start overview.
TEST_P(SplitViewOverviewSessionInClamshellTest,AltSquareBracketNotStartOverview)6770 TEST_P(SplitViewOverviewSessionInClamshellTest,
6771 AltSquareBracketNotStartOverview) {
6772 std::unique_ptr<aura::Window> window1 = CreateTestWindow();
6773 std::unique_ptr<aura::Window> window2 = CreateTestWindow();
6774 wm::ActivateWindow(window1.get());
6775 EXPECT_FALSE(split_view_controller()->InSplitViewMode());
6776 EXPECT_FALSE(InOverviewSession());
6777 // Alt+[
6778 const WMEvent alt_left_square_bracket(WM_EVENT_CYCLE_SNAP_LEFT);
6779 WindowState* window1_state = WindowState::Get(window1.get());
6780 window1_state->OnWMEvent(&alt_left_square_bracket);
6781 EXPECT_EQ(WindowStateType::kLeftSnapped, window1_state->GetStateType());
6782 EXPECT_FALSE(split_view_controller()->InSplitViewMode());
6783 EXPECT_FALSE(InOverviewSession());
6784 // Alt+]
6785 const WMEvent alt_right_square_bracket(WM_EVENT_CYCLE_SNAP_RIGHT);
6786 window1_state->OnWMEvent(&alt_right_square_bracket);
6787 EXPECT_EQ(WindowStateType::kRightSnapped, window1_state->GetStateType());
6788 EXPECT_FALSE(split_view_controller()->InSplitViewMode());
6789 EXPECT_FALSE(InOverviewSession());
6790 }
6791
6792 // Tests using Alt+[ on a left split view window.
TEST_P(SplitViewOverviewSessionInClamshellTest,AltLeftSquareBracketOnLeftSplitViewWindow)6793 TEST_P(SplitViewOverviewSessionInClamshellTest,
6794 AltLeftSquareBracketOnLeftSplitViewWindow) {
6795 std::unique_ptr<aura::Window> snapped_window = CreateTestWindow();
6796 std::unique_ptr<aura::Window> overview_window = CreateTestWindow();
6797 ToggleOverview();
6798 split_view_controller()->SnapWindow(snapped_window.get(),
6799 SplitViewController::LEFT);
6800 WindowState* snapped_window_state = WindowState::Get(snapped_window.get());
6801 EXPECT_EQ(WindowStateType::kLeftSnapped,
6802 snapped_window_state->GetStateType());
6803 EXPECT_TRUE(split_view_controller()->InSplitViewMode());
6804 EXPECT_TRUE(InOverviewSession());
6805 const WMEvent alt_left_square_bracket(WM_EVENT_CYCLE_SNAP_LEFT);
6806 snapped_window_state->OnWMEvent(&alt_left_square_bracket);
6807 EXPECT_EQ(WindowStateType::kNormal, snapped_window_state->GetStateType());
6808 EXPECT_FALSE(split_view_controller()->InSplitViewMode());
6809 EXPECT_FALSE(InOverviewSession());
6810 }
6811
6812 // Tests using Alt+] on a right split view window.
TEST_P(SplitViewOverviewSessionInClamshellTest,AltRightSquareBracketOnRightSplitViewWindow)6813 TEST_P(SplitViewOverviewSessionInClamshellTest,
6814 AltRightSquareBracketOnRightSplitViewWindow) {
6815 std::unique_ptr<aura::Window> snapped_window = CreateTestWindow();
6816 std::unique_ptr<aura::Window> overview_window = CreateTestWindow();
6817 ToggleOverview();
6818 split_view_controller()->SnapWindow(snapped_window.get(),
6819 SplitViewController::RIGHT);
6820 WindowState* snapped_window_state = WindowState::Get(snapped_window.get());
6821 EXPECT_EQ(WindowStateType::kRightSnapped,
6822 snapped_window_state->GetStateType());
6823 EXPECT_TRUE(split_view_controller()->InSplitViewMode());
6824 EXPECT_TRUE(InOverviewSession());
6825 const WMEvent alt_right_square_bracket(WM_EVENT_CYCLE_SNAP_RIGHT);
6826 snapped_window_state->OnWMEvent(&alt_right_square_bracket);
6827 EXPECT_EQ(WindowStateType::kNormal, snapped_window_state->GetStateType());
6828 EXPECT_FALSE(split_view_controller()->InSplitViewMode());
6829 EXPECT_FALSE(InOverviewSession());
6830 }
6831
6832 // Tests using Alt+[ on a right split view window, and Alt+] on a left split
6833 // view window.
TEST_P(SplitViewOverviewSessionInClamshellTest,AltSquareBracketOnSplitViewWindow)6834 TEST_P(SplitViewOverviewSessionInClamshellTest,
6835 AltSquareBracketOnSplitViewWindow) {
6836 std::unique_ptr<aura::Window> snapped_window = CreateTestWindow();
6837 std::unique_ptr<aura::Window> overview_window = CreateTestWindow();
6838 // Enter clamshell split view with |snapped_window| on the right.
6839 ToggleOverview();
6840 split_view_controller()->SnapWindow(snapped_window.get(),
6841 SplitViewController::RIGHT);
6842 wm::ActivateWindow(snapped_window.get());
6843 WindowState* snapped_window_state = WindowState::Get(snapped_window.get());
6844 EXPECT_EQ(WindowStateType::kRightSnapped,
6845 snapped_window_state->GetStateType());
6846 EXPECT_EQ(SplitViewController::State::kRightSnapped,
6847 split_view_controller()->state());
6848 EXPECT_EQ(snapped_window.get(), split_view_controller()->right_window());
6849 EXPECT_TRUE(InOverviewSession());
6850 // Test using Alt+[ to put |snapped_window| on the left.
6851 const WMEvent alt_left_square_bracket(WM_EVENT_CYCLE_SNAP_LEFT);
6852 snapped_window_state->OnWMEvent(&alt_left_square_bracket);
6853 EXPECT_TRUE(wm::IsActiveWindow(snapped_window.get()));
6854 EXPECT_EQ(WindowStateType::kLeftSnapped,
6855 snapped_window_state->GetStateType());
6856 EXPECT_EQ(SplitViewController::State::kLeftSnapped,
6857 split_view_controller()->state());
6858 EXPECT_EQ(snapped_window.get(), split_view_controller()->left_window());
6859 EXPECT_TRUE(InOverviewSession());
6860 // Test using Alt+] to put |snapped_window| on the right.
6861 const WMEvent alt_right_square_bracket(WM_EVENT_CYCLE_SNAP_RIGHT);
6862 snapped_window_state->OnWMEvent(&alt_right_square_bracket);
6863 EXPECT_TRUE(wm::IsActiveWindow(snapped_window.get()));
6864 EXPECT_EQ(WindowStateType::kRightSnapped,
6865 snapped_window_state->GetStateType());
6866 EXPECT_EQ(SplitViewController::State::kRightSnapped,
6867 split_view_controller()->state());
6868 EXPECT_EQ(snapped_window.get(), split_view_controller()->right_window());
6869 EXPECT_TRUE(InOverviewSession());
6870 }
6871
6872 using SplitViewOverviewSessionInClamshellTestMultiDisplayOnly =
6873 SplitViewOverviewSessionInClamshellTest;
6874
6875 // Test |SplitViewController::Get|.
TEST_P(SplitViewOverviewSessionInClamshellTestMultiDisplayOnly,GetSplitViewController)6876 TEST_P(SplitViewOverviewSessionInClamshellTestMultiDisplayOnly,
6877 GetSplitViewController) {
6878 UpdateDisplay("800x600,800x600");
6879 aura::Window::Windows root_windows = Shell::GetAllRootWindows();
6880 ASSERT_EQ(2u, root_windows.size());
6881 const gfx::Rect bounds_within_root1(0, 0, 400, 400);
6882 const gfx::Rect bounds_within_root2(800, 0, 400, 400);
6883 std::unique_ptr<aura::Window> window1 = CreateTestWindow(bounds_within_root1);
6884 std::unique_ptr<aura::Window> window2 = CreateTestWindow(bounds_within_root2);
6885 EXPECT_EQ(root_windows[0],
6886 SplitViewController::Get(window1.get())->root_window());
6887 EXPECT_EQ(root_windows[1],
6888 SplitViewController::Get(window2.get())->root_window());
6889 }
6890
6891 // Test |SplitViewController::GetSnappedWindowBoundsInScreen|.
TEST_P(SplitViewOverviewSessionInClamshellTestMultiDisplayOnly,GetSnappedBounds)6892 TEST_P(SplitViewOverviewSessionInClamshellTestMultiDisplayOnly,
6893 GetSnappedBounds) {
6894 UpdateDisplay("800x600,800x600");
6895 aura::Window::Windows root_windows = Shell::GetAllRootWindows();
6896 ASSERT_EQ(2u, root_windows.size());
6897 const int height = 600 - ShelfConfig::Get()->shelf_size();
6898 ASSERT_EQ(gfx::Rect(0, 0, 800, height),
6899 screen_util::GetDisplayWorkAreaBoundsInScreenForActiveDeskContainer(
6900 root_windows[0]));
6901 ASSERT_EQ(gfx::Rect(800, 0, 800, height),
6902 screen_util::GetDisplayWorkAreaBoundsInScreenForActiveDeskContainer(
6903 root_windows[1]));
6904
6905 EXPECT_EQ(
6906 gfx::Rect(0, 0, 400, height),
6907 SplitViewController::Get(root_windows[0])
6908 ->GetSnappedWindowBoundsInScreen(
6909 SplitViewController::LEFT, /*window_for_minimum_size=*/nullptr));
6910 EXPECT_EQ(
6911 gfx::Rect(400, 0, 400, height),
6912 SplitViewController::Get(root_windows[0])
6913 ->GetSnappedWindowBoundsInScreen(
6914 SplitViewController::RIGHT, /*window_for_minimum_size=*/nullptr));
6915 EXPECT_EQ(
6916 gfx::Rect(800, 0, 400, height),
6917 SplitViewController::Get(root_windows[1])
6918 ->GetSnappedWindowBoundsInScreen(
6919 SplitViewController::LEFT, /*window_for_minimum_size=*/nullptr));
6920 EXPECT_EQ(
6921 gfx::Rect(1200, 0, 400, height),
6922 SplitViewController::Get(root_windows[1])
6923 ->GetSnappedWindowBoundsInScreen(
6924 SplitViewController::RIGHT, /*window_for_minimum_size=*/nullptr));
6925 }
6926
6927 // Test that if clamshell split view is started by snapping a window that is the
6928 // only overview window, then split view ends as soon as it starts, and overview
6929 // ends along with it.
TEST_P(SplitViewOverviewSessionInClamshellTestMultiDisplayOnly,SplitViewEndsImmediatelyIfOverviewIsEmpty)6930 TEST_P(SplitViewOverviewSessionInClamshellTestMultiDisplayOnly,
6931 SplitViewEndsImmediatelyIfOverviewIsEmpty) {
6932 UpdateDisplay("800x600,800x600");
6933 aura::Window::Windows root_windows = Shell::GetAllRootWindows();
6934 ASSERT_EQ(2u, root_windows.size());
6935 const gfx::Rect bounds_within_root1(0, 0, 400, 400);
6936 std::unique_ptr<aura::Window> window = CreateTestWindow(bounds_within_root1);
6937 ToggleOverview();
6938 SplitViewController::Get(root_windows[0])
6939 ->SnapWindow(window.get(), SplitViewController::LEFT);
6940 EXPECT_FALSE(InOverviewSession());
6941 EXPECT_FALSE(SplitViewController::Get(root_windows[0])->InSplitViewMode());
6942 }
6943
6944 // Test that if clamshell split view is started by snapping a window on one
6945 // display while there is an overview window on another display, then split view
6946 // stays active (instead of ending as soon as it starts), and overview also
6947 // stays active. Then close the overview window and verify that split view and
6948 // overview are ended.
TEST_P(SplitViewOverviewSessionInClamshellTestMultiDisplayOnly,SplitViewViableWithOverviewWindowOnOtherDisplay)6949 TEST_P(SplitViewOverviewSessionInClamshellTestMultiDisplayOnly,
6950 SplitViewViableWithOverviewWindowOnOtherDisplay) {
6951 UpdateDisplay("800x600,800x600");
6952 aura::Window::Windows root_windows = Shell::GetAllRootWindows();
6953 ASSERT_EQ(2u, root_windows.size());
6954 const gfx::Rect bounds_within_root1(0, 0, 400, 400);
6955 const gfx::Rect bounds_within_root2(800, 0, 400, 400);
6956 std::unique_ptr<aura::Window> window1 = CreateTestWindow(bounds_within_root1);
6957 std::unique_ptr<aura::Window> window2 = CreateTestWindow(bounds_within_root2);
6958 ToggleOverview();
6959 SplitViewController::Get(root_windows[0])
6960 ->SnapWindow(window1.get(), SplitViewController::LEFT);
6961 EXPECT_TRUE(SplitViewController::Get(root_windows[0])->InSplitViewMode());
6962 EXPECT_TRUE(InOverviewSession());
6963 window2.reset();
6964 EXPECT_FALSE(SplitViewController::Get(root_windows[0])->InSplitViewMode());
6965 EXPECT_FALSE(InOverviewSession());
6966 }
6967
6968 // Test dragging to snap an overview item on an external display.
TEST_P(SplitViewOverviewSessionInClamshellTestMultiDisplayOnly,DraggingOnExternalDisplay)6969 TEST_P(SplitViewOverviewSessionInClamshellTestMultiDisplayOnly,
6970 DraggingOnExternalDisplay) {
6971 UpdateDisplay("800x600,800x600");
6972 aura::Window::Windows root_windows = Shell::GetAllRootWindows();
6973 ASSERT_EQ(2u, root_windows.size());
6974 const gfx::Rect bounds_within_root2(800, 0, 400, 400);
6975 std::unique_ptr<aura::Window> window1 = CreateTestWindow(bounds_within_root2);
6976 std::unique_ptr<aura::Window> window2 = CreateTestWindow(bounds_within_root2);
6977 ToggleOverview();
6978 OverviewGrid* grid_on_root2 =
6979 overview_session()->GetGridWithRootWindow(root_windows[1]);
6980 OverviewItem* item1 = grid_on_root2->GetOverviewItemContaining(window1.get());
6981 OverviewItem* item2 = grid_on_root2->GetOverviewItemContaining(window2.get());
6982 SplitViewController* split_view_controller =
6983 SplitViewController::Get(root_windows[1]);
6984 SplitViewDragIndicators* indicators =
6985 grid_on_root2->split_view_drag_indicators();
6986
6987 Shell::Get()->cursor_manager()->SetDisplay(
6988 display::Screen::GetScreen()->GetDisplayNearestWindow(root_windows[1]));
6989 overview_session()->InitiateDrag(item1, item1->target_bounds().CenterPoint(),
6990 /*is_touch_dragging=*/false);
6991 const gfx::PointF right_snap_point(1599.f, 300.f);
6992 overview_session()->Drag(item1, right_snap_point);
6993 EXPECT_EQ(SplitViewDragIndicators::WindowDraggingState::kToSnapRight,
6994 indicators->current_window_dragging_state());
6995 EXPECT_EQ(
6996 SplitViewController::Get(root_windows[1])
6997 ->GetSnappedWindowBoundsInScreen(SplitViewController::LEFT,
6998 /*window_for_minimum_size=*/nullptr),
6999 grid_on_root2->bounds());
7000 overview_session()->CompleteDrag(item1, right_snap_point);
7001 EXPECT_EQ(SplitViewController::State::kRightSnapped,
7002 split_view_controller->state());
7003 EXPECT_EQ(window1.get(), split_view_controller->right_window());
7004
7005 overview_session()->InitiateDrag(item2, item2->target_bounds().CenterPoint(),
7006 /*is_touch_dragging=*/false);
7007 const gfx::PointF left_of_middle(1150.f, 300.f);
7008 overview_session()->Drag(item2, left_of_middle);
7009 EXPECT_EQ(SplitViewDragIndicators::WindowDraggingState::kFromOverview,
7010 indicators->current_window_dragging_state());
7011 overview_session()->CompleteDrag(item2, left_of_middle);
7012 EXPECT_EQ(SplitViewController::State::kRightSnapped,
7013 split_view_controller->state());
7014 EXPECT_EQ(window1.get(), split_view_controller->right_window());
7015
7016 overview_session()->InitiateDrag(item2, item2->target_bounds().CenterPoint(),
7017 /*is_touch_dragging=*/false);
7018 const gfx::PointF left_snap_point(810.f, 300.f);
7019 overview_session()->Drag(item2, left_snap_point);
7020 EXPECT_EQ(SplitViewDragIndicators::WindowDraggingState::kToSnapLeft,
7021 indicators->current_window_dragging_state());
7022 overview_session()->CompleteDrag(item2, left_snap_point);
7023 EXPECT_EQ(SplitViewController::State::kNoSnap,
7024 split_view_controller->state());
7025 }
7026
7027 // Test dragging from one display to another.
TEST_P(SplitViewOverviewSessionInClamshellTestMultiDisplayOnly,MultiDisplayDragging)7028 TEST_P(SplitViewOverviewSessionInClamshellTestMultiDisplayOnly,
7029 MultiDisplayDragging) {
7030 wm::CursorManager* cursor_manager = Shell::Get()->cursor_manager();
7031 UpdateDisplay("800x600,800x600");
7032 aura::Window::Windows root_windows = Shell::GetAllRootWindows();
7033 ASSERT_EQ(2u, root_windows.size());
7034 const display::Display display_with_root1 =
7035 display::Screen::GetScreen()->GetDisplayNearestWindow(root_windows[0]);
7036 const display::Display display_with_root2 =
7037 display::Screen::GetScreen()->GetDisplayNearestWindow(root_windows[1]);
7038 const gfx::Rect bounds_within_root1(0, 0, 400, 400);
7039 const gfx::Rect bounds_within_root2(800, 0, 400, 400);
7040 std::unique_ptr<aura::Window> window1 = CreateTestWindow(bounds_within_root1);
7041 std::unique_ptr<aura::Window> window2 = CreateTestWindow(bounds_within_root1);
7042 std::unique_ptr<aura::Window> window3 = CreateTestWindow(bounds_within_root2);
7043 ToggleOverview();
7044 OverviewGrid* grid_on_root1 =
7045 overview_session()->GetGridWithRootWindow(root_windows[0]);
7046 OverviewGrid* grid_on_root2 =
7047 overview_session()->GetGridWithRootWindow(root_windows[1]);
7048 OverviewItem* item1 = grid_on_root1->GetOverviewItemContaining(window1.get());
7049 SplitViewDragIndicators* indicators_on_root1 =
7050 grid_on_root1->split_view_drag_indicators();
7051 SplitViewDragIndicators* indicators_on_root2 =
7052 grid_on_root2->split_view_drag_indicators();
7053
7054 ASSERT_EQ(display_with_root1.id(), cursor_manager->GetDisplay().id());
7055 overview_session()->InitiateDrag(item1, item1->target_bounds().CenterPoint(),
7056 /*is_touch_dragging=*/false);
7057 EXPECT_EQ(SplitViewDragIndicators::WindowDraggingState::kNoDrag,
7058 indicators_on_root1->current_window_dragging_state());
7059 EXPECT_EQ(display_with_root1.work_area(), grid_on_root1->bounds());
7060 EXPECT_EQ(SplitViewDragIndicators::WindowDraggingState::kNoDrag,
7061 indicators_on_root2->current_window_dragging_state());
7062 EXPECT_EQ(display_with_root2.work_area(), grid_on_root2->bounds());
7063
7064 const gfx::PointF root1_left_snap_point(0.f, 300.f);
7065 overview_session()->Drag(item1, root1_left_snap_point);
7066 EXPECT_EQ(SplitViewDragIndicators::WindowDraggingState::kToSnapLeft,
7067 indicators_on_root1->current_window_dragging_state());
7068 EXPECT_EQ(
7069 SplitViewController::Get(root_windows[0])
7070 ->GetSnappedWindowBoundsInScreen(SplitViewController::RIGHT,
7071 /*window_for_minimum_size=*/nullptr),
7072 grid_on_root1->bounds());
7073 EXPECT_EQ(SplitViewDragIndicators::WindowDraggingState::kOtherDisplay,
7074 indicators_on_root2->current_window_dragging_state());
7075 EXPECT_EQ(display_with_root2.work_area(), grid_on_root2->bounds());
7076
7077 const gfx::PointF root1_middle_point(400.f, 300.f);
7078 overview_session()->Drag(item1, root1_middle_point);
7079 EXPECT_EQ(SplitViewDragIndicators::WindowDraggingState::kFromOverview,
7080 indicators_on_root1->current_window_dragging_state());
7081 EXPECT_EQ(display_with_root1.work_area(), grid_on_root1->bounds());
7082 EXPECT_EQ(SplitViewDragIndicators::WindowDraggingState::kOtherDisplay,
7083 indicators_on_root2->current_window_dragging_state());
7084 EXPECT_EQ(display_with_root2.work_area(), grid_on_root2->bounds());
7085
7086 const gfx::PointF root1_right_snap_point(799.f, 300.f);
7087 overview_session()->Drag(item1, root1_right_snap_point);
7088 EXPECT_EQ(SplitViewDragIndicators::WindowDraggingState::kToSnapRight,
7089 indicators_on_root1->current_window_dragging_state());
7090 EXPECT_EQ(
7091 SplitViewController::Get(root_windows[0])
7092 ->GetSnappedWindowBoundsInScreen(SplitViewController::LEFT,
7093 /*window_for_minimum_size=*/nullptr),
7094 grid_on_root1->bounds());
7095 EXPECT_EQ(SplitViewDragIndicators::WindowDraggingState::kOtherDisplay,
7096 indicators_on_root2->current_window_dragging_state());
7097 EXPECT_EQ(display_with_root2.work_area(), grid_on_root2->bounds());
7098
7099 const gfx::PointF root2_left_snap_point(800.f, 300.f);
7100 cursor_manager->SetDisplay(display_with_root2);
7101 overview_session()->Drag(item1, root2_left_snap_point);
7102 EXPECT_EQ(SplitViewDragIndicators::WindowDraggingState::kOtherDisplay,
7103 indicators_on_root1->current_window_dragging_state());
7104 EXPECT_EQ(display_with_root1.work_area(), grid_on_root1->bounds());
7105 EXPECT_EQ(SplitViewDragIndicators::WindowDraggingState::kToSnapLeft,
7106 indicators_on_root2->current_window_dragging_state());
7107 EXPECT_EQ(
7108 SplitViewController::Get(root_windows[1])
7109 ->GetSnappedWindowBoundsInScreen(SplitViewController::RIGHT,
7110 /*window_for_minimum_size=*/nullptr),
7111 grid_on_root2->bounds());
7112
7113 const gfx::PointF root2_left_snap_point_away_from_edge(816.f, 300.f);
7114 overview_session()->Drag(item1, root2_left_snap_point_away_from_edge);
7115 EXPECT_EQ(SplitViewDragIndicators::WindowDraggingState::kOtherDisplay,
7116 indicators_on_root1->current_window_dragging_state());
7117 EXPECT_EQ(display_with_root1.work_area(), grid_on_root1->bounds());
7118 EXPECT_EQ(SplitViewDragIndicators::WindowDraggingState::kToSnapLeft,
7119 indicators_on_root2->current_window_dragging_state());
7120 EXPECT_EQ(
7121 SplitViewController::Get(root_windows[1])
7122 ->GetSnappedWindowBoundsInScreen(SplitViewController::RIGHT,
7123 /*window_for_minimum_size=*/nullptr),
7124 grid_on_root2->bounds());
7125
7126 const gfx::PointF root2_right_snap_point(1599.f, 300.f);
7127 overview_session()->Drag(item1, root2_right_snap_point);
7128 EXPECT_EQ(SplitViewDragIndicators::WindowDraggingState::kOtherDisplay,
7129 indicators_on_root1->current_window_dragging_state());
7130 EXPECT_EQ(display_with_root1.work_area(), grid_on_root1->bounds());
7131 EXPECT_EQ(SplitViewDragIndicators::WindowDraggingState::kToSnapRight,
7132 indicators_on_root2->current_window_dragging_state());
7133 EXPECT_EQ(
7134 SplitViewController::Get(root_windows[1])
7135 ->GetSnappedWindowBoundsInScreen(SplitViewController::LEFT,
7136 /*window_for_minimum_size=*/nullptr),
7137 grid_on_root2->bounds());
7138
7139 const gfx::PointF root2_middle_point(1200.f, 300.f);
7140 overview_session()->Drag(item1, root2_middle_point);
7141 EXPECT_EQ(SplitViewDragIndicators::WindowDraggingState::kOtherDisplay,
7142 indicators_on_root1->current_window_dragging_state());
7143 EXPECT_EQ(display_with_root1.work_area(), grid_on_root1->bounds());
7144 EXPECT_EQ(SplitViewDragIndicators::WindowDraggingState::kFromOverview,
7145 indicators_on_root2->current_window_dragging_state());
7146 EXPECT_EQ(display_with_root2.work_area(), grid_on_root2->bounds());
7147
7148 overview_session()->CompleteDrag(item1, root2_middle_point);
7149 EXPECT_EQ(SplitViewDragIndicators::WindowDraggingState::kNoDrag,
7150 indicators_on_root1->current_window_dragging_state());
7151 EXPECT_EQ(display_with_root1.work_area(), grid_on_root1->bounds());
7152 EXPECT_EQ(SplitViewDragIndicators::WindowDraggingState::kNoDrag,
7153 indicators_on_root2->current_window_dragging_state());
7154 EXPECT_EQ(display_with_root2.work_area(), grid_on_root2->bounds());
7155 }
7156
7157 // Verify the drop target positions for multi-display dragging.
TEST_P(SplitViewOverviewSessionInClamshellTestMultiDisplayOnly,DropTargetPositionTest)7158 TEST_P(SplitViewOverviewSessionInClamshellTestMultiDisplayOnly,
7159 DropTargetPositionTest) {
7160 wm::CursorManager* cursor_manager = Shell::Get()->cursor_manager();
7161 UpdateDisplay("800x600,800x600");
7162 aura::Window::Windows root_windows = Shell::GetAllRootWindows();
7163 ASSERT_EQ(2u, root_windows.size());
7164 const display::Display display_with_root1 =
7165 display::Screen::GetScreen()->GetDisplayNearestWindow(root_windows[0]);
7166 const display::Display display_with_root2 =
7167 display::Screen::GetScreen()->GetDisplayNearestWindow(root_windows[1]);
7168 const gfx::Rect bounds_within_root1(0, 0, 400, 400);
7169 const gfx::Rect bounds_within_root2(800, 0, 400, 400);
7170 // Named for MRU order, which is in reverse of creation order.
7171 std::unique_ptr<aura::Window> window6 = CreateTestWindow(bounds_within_root2);
7172 std::unique_ptr<aura::Window> window5 = CreateTestWindow(bounds_within_root1);
7173 std::unique_ptr<aura::Window> window4 = CreateTestWindow(bounds_within_root2);
7174 std::unique_ptr<aura::Window> window3 = CreateTestWindow(bounds_within_root1);
7175 std::unique_ptr<aura::Window> window2 = CreateTestWindow(bounds_within_root2);
7176 std::unique_ptr<aura::Window> window1 = CreateTestWindow(bounds_within_root1);
7177 ToggleOverview();
7178 OverviewGrid* grid1 =
7179 overview_session()->GetGridWithRootWindow(root_windows[0]);
7180 OverviewGrid* grid2 =
7181 overview_session()->GetGridWithRootWindow(root_windows[1]);
7182 OverviewItem* item4 = grid2->GetOverviewItemContaining(window4.get());
7183 // Start dragging |item4| from |grid2|.
7184 cursor_manager->SetDisplay(display_with_root2);
7185 overview_session()->InitiateDrag(item4, item4->target_bounds().CenterPoint(),
7186 /*is_touch_dragging=*/false);
7187 overview_session()->Drag(item4, gfx::PointF(1200.f, 0.f));
7188 // On the grid where the drag starts (|grid2|), the drop target is inserted at
7189 // the index immediately following the dragged item (|item4|).
7190 ASSERT_EQ(4u, grid2->window_list().size());
7191 EXPECT_EQ(grid2->GetDropTarget(), grid2->window_list()[2].get());
7192 // Drag over |grid1|.
7193 cursor_manager->SetDisplay(display_with_root1);
7194 overview_session()->Drag(item4, gfx::PointF(400.f, 0.f));
7195 // On other grids (such as |grid1|), the drop target is inserted at the
7196 // correct position according to MRU order (between the overview items for
7197 // |window3| and |window5|).
7198 ASSERT_EQ(4u, grid1->window_list().size());
7199 EXPECT_EQ(grid1->GetDropTarget(), grid1->window_list()[2].get());
7200 }
7201
7202 // Verify that the drop target in each overview grid has the correct bounds when
7203 // a maximized window is being dragged.
TEST_P(SplitViewOverviewSessionInClamshellTestMultiDisplayOnly,DropTargetBoundsForMaximizedWindowDraggedToOtherDisplay)7204 TEST_P(SplitViewOverviewSessionInClamshellTestMultiDisplayOnly,
7205 DropTargetBoundsForMaximizedWindowDraggedToOtherDisplay) {
7206 UpdateDisplay("1000x400,1000x400/l");
7207 std::unique_ptr<aura::Window> window = CreateTestWindow();
7208 WindowState::Get(window.get())->Maximize();
7209 ToggleOverview();
7210 OverviewItem* item = GetOverviewItemForWindow(window.get());
7211 // Verify that |item| is letter boxed. The bounds of |item|, minus the margin
7212 // should have an aspect ratio of 2 : 1.
7213 gfx::RectF item_bounds = item->target_bounds();
7214 item_bounds.Inset(gfx::InsetsF(kWindowMargin));
7215 EXPECT_EQ(OverviewGridWindowFillMode::kLetterBoxed,
7216 item->GetWindowDimensionsType());
7217 EXPECT_EQ(2.f, item_bounds.width() / item_bounds.height());
7218 overview_session()->InitiateDrag(item, item->target_bounds().CenterPoint(),
7219 /*is_touch_dragging=*/false);
7220 Shell::Get()->cursor_manager()->SetDisplay(
7221 display::test::DisplayManagerTestApi(display_manager())
7222 .GetSecondaryDisplay());
7223 overview_session()->Drag(item, gfx::PointF(1200.f, 0.f));
7224 OverviewItem* drop_target = GetDropTarget(1);
7225 ASSERT_TRUE(drop_target);
7226 // Verify that |drop_target| is effectively pillar boxed. Avoid calling
7227 // |OverviewItem::GetWindowDimensionsType|, because it does not work for drop
7228 // targets (and that is okay). The bounds of |drop_target|, minus the margin
7229 // should have an aspect ratio of 1 : 2.
7230 gfx::RectF drop_target_bounds = drop_target->target_bounds();
7231 drop_target_bounds.Inset(gfx::InsetsF(kWindowMargin));
7232 EXPECT_EQ(0.5f, drop_target_bounds.width() / drop_target_bounds.height());
7233 }
7234
7235 // Verify that the drop target in each overview grid has bounds representing
7236 // anticipation that if the dragged window is dropped into that grid, it will
7237 // shrink to fit into the corresponding work area.
TEST_P(SplitViewOverviewSessionInClamshellTestMultiDisplayOnly,DropTargetBoundsOnDisplayWhereDraggedWindowDoesNotFitIntoWorkArea)7238 TEST_P(SplitViewOverviewSessionInClamshellTestMultiDisplayOnly,
7239 DropTargetBoundsOnDisplayWhereDraggedWindowDoesNotFitIntoWorkArea) {
7240 UpdateDisplay("600x600,1200x1200");
7241 // Drags |item| from the right display to the left display and back, and
7242 // returns the bounds of the drop target that appears on the left display.
7243 const auto root1_drop_target_bounds = [this](OverviewItem* item) {
7244 wm::CursorManager* cursor_manager = Shell::Get()->cursor_manager();
7245 const gfx::PointF drag_starting_point = item->target_bounds().CenterPoint();
7246 display::test::DisplayManagerTestApi display_manager_test(
7247 display_manager());
7248 cursor_manager->SetDisplay(display_manager_test.GetSecondaryDisplay());
7249 overview_session()->InitiateDrag(item, drag_starting_point,
7250 /*is_touch_dragging=*/false);
7251 cursor_manager->SetDisplay(
7252 display::Screen::GetScreen()->GetPrimaryDisplay());
7253 overview_session()->Drag(item, gfx::PointF(300.f, 0.f));
7254 cursor_manager->SetDisplay(display_manager_test.GetSecondaryDisplay());
7255 overview_session()->Drag(item, drag_starting_point);
7256 DCHECK(GetDropTarget(0));
7257 const gfx::RectF result = GetDropTarget(0)->target_bounds();
7258 overview_session()->CompleteDrag(item, drag_starting_point);
7259 return result;
7260 };
7261
7262 // |window1| has the size that |window2| would become if moved to the left
7263 // display.
7264 std::unique_ptr<aura::Window> window1 =
7265 CreateTestWindow(gfx::Rect(600, 0, 600, 400));
7266 std::unique_ptr<aura::Window> window2 =
7267 CreateTestWindow(gfx::Rect(600, 0, 1000, 400));
7268 // |window3| has the size that |window4| would become if moved to the left
7269 // display.
7270 std::unique_ptr<aura::Window> window3 = CreateTestWindow(
7271 gfx::Rect(600, 0, 400, 600 - ShelfConfig::Get()->shelf_size()));
7272 std::unique_ptr<aura::Window> window4 =
7273 CreateTestWindow(gfx::Rect(600, 0, 400, 1000));
7274
7275 ToggleOverview();
7276 OverviewItem* item1 = GetOverviewItemForWindow(window1.get());
7277 OverviewItem* item2 = GetOverviewItemForWindow(window2.get());
7278 OverviewItem* item3 = GetOverviewItemForWindow(window3.get());
7279 OverviewItem* item4 = GetOverviewItemForWindow(window4.get());
7280
7281 // For good test coverage in each case, the dragged window and the drop target
7282 // have different |OverviewGridWindowFillMode| values.
7283 EXPECT_EQ(OverviewGridWindowFillMode::kNormal,
7284 item1->GetWindowDimensionsType());
7285 EXPECT_EQ(OverviewGridWindowFillMode::kLetterBoxed,
7286 item2->GetWindowDimensionsType());
7287 EXPECT_EQ(OverviewGridWindowFillMode::kNormal,
7288 item3->GetWindowDimensionsType());
7289 EXPECT_EQ(OverviewGridWindowFillMode::kPillarBoxed,
7290 item4->GetWindowDimensionsType());
7291
7292 EXPECT_EQ(root1_drop_target_bounds(item1), root1_drop_target_bounds(item2));
7293 EXPECT_EQ(root1_drop_target_bounds(item3), root1_drop_target_bounds(item4));
7294 }
7295
7296 // Test dragging from one overview grid and dropping into another overview grid.
TEST_P(SplitViewOverviewSessionInClamshellTestMultiDisplayOnly,DragAndDropIntoAnotherOverviewGrid)7297 TEST_P(SplitViewOverviewSessionInClamshellTestMultiDisplayOnly,
7298 DragAndDropIntoAnotherOverviewGrid) {
7299 UpdateDisplay("800x600,800x600");
7300 aura::Window::Windows root_windows = Shell::GetAllRootWindows();
7301 ASSERT_EQ(2u, root_windows.size());
7302 std::unique_ptr<aura::Window> window = CreateTestWindow();
7303 ASSERT_EQ(root_windows[0], window->GetRootWindow());
7304 ToggleOverview();
7305 OverviewGrid* grid1 =
7306 overview_session()->GetGridWithRootWindow(root_windows[0]);
7307 OverviewGrid* grid2 =
7308 overview_session()->GetGridWithRootWindow(root_windows[1]);
7309
7310 // Drag |window| from |grid1| and drop into |grid2|.
7311 ui::test::EventGenerator* generator = GetEventGenerator();
7312 generator->MoveMouseTo(
7313 gfx::ToRoundedPoint(grid1->GetOverviewItemContaining(window.get())
7314 ->target_bounds()
7315 .CenterPoint()));
7316 generator->PressLeftButton();
7317 Shell::Get()->cursor_manager()->SetDisplay(
7318 display::Screen::GetScreen()->GetDisplayNearestWindow(root_windows[1]));
7319 generator->MoveMouseTo(1200, 300);
7320 generator->ReleaseLeftButton();
7321
7322 EXPECT_EQ(root_windows[1], window->GetRootWindow());
7323 EXPECT_TRUE(grid1->empty());
7324 OverviewItem* item = grid2->GetOverviewItemContaining(window.get());
7325 ASSERT_TRUE(item);
7326 EXPECT_EQ(root_windows[1], item->root_window());
7327 }
7328
7329 // Test that overview widgets are stacked in the correct order after an overview
7330 // window is dragged from one overview grid and dropped into another. Also test
7331 // that the destination overview grid is arranged in the correct order.
TEST_P(SplitViewOverviewSessionInClamshellTestMultiDisplayOnly,OverviewWidgetStackingOrderAndGridOrderWithMultiDisplayDragging)7332 TEST_P(SplitViewOverviewSessionInClamshellTestMultiDisplayOnly,
7333 OverviewWidgetStackingOrderAndGridOrderWithMultiDisplayDragging) {
7334 UpdateDisplay("800x600,800x600");
7335 aura::Window::Windows root_windows = Shell::GetAllRootWindows();
7336 ASSERT_EQ(2u, root_windows.size());
7337 const gfx::Rect bounds_within_root1(0, 0, 400, 400);
7338 const gfx::Rect bounds_within_root2(800, 0, 400, 400);
7339 std::unique_ptr<aura::Window> window3 = CreateTestWindow(bounds_within_root2);
7340 std::unique_ptr<aura::Window> window2 = CreateTestWindow(bounds_within_root1);
7341 std::unique_ptr<aura::Window> window1 = CreateTestWindow(bounds_within_root2);
7342 aura::Window* parent_on_root1 = window2->parent();
7343 aura::Window* parent_on_root2 = window1->parent();
7344 ASSERT_NE(parent_on_root1, parent_on_root2);
7345 ASSERT_EQ(window3->parent(), parent_on_root2);
7346 ToggleOverview();
7347 OverviewItem* item1 = GetOverviewItemForWindow(window1.get());
7348 OverviewItem* item2 = GetOverviewItemForWindow(window2.get());
7349 OverviewItem* item3 = GetOverviewItemForWindow(window3.get());
7350
7351 ASSERT_EQ(root_windows[0], item2->root_window());
7352 // Verify that |item1| is stacked above |item3| (because we created |window1|
7353 // after |window3|).
7354 EXPECT_GT(IndexOf(item1->item_widget()->GetNativeWindow(), parent_on_root2),
7355 IndexOf(item3->item_widget()->GetNativeWindow(), parent_on_root2));
7356 // Verify that the item widget for each window is stacked below that window.
7357 EXPECT_LT(IndexOf(item1->item_widget()->GetNativeWindow(), parent_on_root2),
7358 IndexOf(window1.get(), parent_on_root2));
7359 EXPECT_LT(IndexOf(item2->item_widget()->GetNativeWindow(), parent_on_root1),
7360 IndexOf(window2.get(), parent_on_root1));
7361 EXPECT_LT(IndexOf(item3->item_widget()->GetNativeWindow(), parent_on_root2),
7362 IndexOf(window3.get(), parent_on_root2));
7363
7364 // Drag |item2| from the left display and drop into the right display.
7365 ui::test::EventGenerator* generator = GetEventGenerator();
7366 generator->MoveMouseTo(
7367 gfx::ToRoundedPoint(item2->target_bounds().CenterPoint()));
7368 generator->PressLeftButton();
7369 Shell::Get()->cursor_manager()->SetDisplay(
7370 display::Screen::GetScreen()->GetDisplayNearestWindow(root_windows[1]));
7371 generator->MoveMouseTo(1200, 300);
7372 generator->ReleaseLeftButton();
7373 // |item2| is now a dangling pointer and we have to refresh it, because when
7374 // an overview window is dragged from one grid and dropped into another, the
7375 // original item is destroyed and a new one is created.
7376 item2 = GetOverviewItemForWindow(window2.get());
7377
7378 ASSERT_EQ(window2->parent(), parent_on_root2);
7379 ASSERT_EQ(root_windows[1], item2->root_window());
7380 // With all three items on one grid, verify that their stacking order
7381 // corresponds to the MRU order of the windows. The new |item2| is sandwiched
7382 // between |item1| and |item3|.
7383 EXPECT_GT(IndexOf(item1->item_widget()->GetNativeWindow(), parent_on_root2),
7384 IndexOf(item2->item_widget()->GetNativeWindow(), parent_on_root2));
7385 EXPECT_GT(IndexOf(item2->item_widget()->GetNativeWindow(), parent_on_root2),
7386 IndexOf(item3->item_widget()->GetNativeWindow(), parent_on_root2));
7387 // Verify that the item widget for the new |item2| is stacked below |window2|.
7388 EXPECT_LT(IndexOf(item2->item_widget()->GetNativeWindow(), parent_on_root2),
7389 IndexOf(window2.get(), parent_on_root2));
7390
7391 // Verify that the right grid is in MRU order.
7392 const std::vector<aura::Window*> expected_order = {
7393 window1.get(), window2.get(), window3.get()};
7394 EXPECT_EQ(expected_order,
7395 overview_controller()->GetWindowsListInOverviewGridsForTest());
7396 }
7397
7398 // Test dragging from one display to another and then snapping.
TEST_P(SplitViewOverviewSessionInClamshellTestMultiDisplayOnly,DragFromOneDisplayToAnotherAndSnap)7399 TEST_P(SplitViewOverviewSessionInClamshellTestMultiDisplayOnly,
7400 DragFromOneDisplayToAnotherAndSnap) {
7401 UpdateDisplay("800x600,800x600");
7402 aura::Window::Windows root_windows = Shell::GetAllRootWindows();
7403 ASSERT_EQ(2u, root_windows.size());
7404 SplitViewController* split_view_controller1 =
7405 SplitViewController::Get(root_windows[0]);
7406 SplitViewController* split_view_controller2 =
7407 SplitViewController::Get(root_windows[1]);
7408 const gfx::Rect bounds_within_root1(0, 0, 400, 400);
7409 std::unique_ptr<aura::Window> window1 = CreateTestWindow(bounds_within_root1);
7410 std::unique_ptr<aura::Window> window2 = CreateTestWindow(bounds_within_root1);
7411 ToggleOverview();
7412 ui::test::EventGenerator* generator = GetEventGenerator();
7413 generator->MoveMouseTo(gfx::ToRoundedPoint(
7414 GetOverviewItemForWindow(window2.get())->target_bounds().CenterPoint()));
7415 generator->PressLeftButton();
7416 Shell::Get()->cursor_manager()->SetDisplay(
7417 display::Screen::GetScreen()->GetDisplayNearestWindow(root_windows[1]));
7418 generator->MoveMouseTo(800, 300);
7419 generator->ReleaseLeftButton();
7420 EXPECT_EQ(SplitViewController::State::kNoSnap,
7421 split_view_controller1->state());
7422 EXPECT_EQ(SplitViewController::State::kLeftSnapped,
7423 split_view_controller2->state());
7424 EXPECT_EQ(window2.get(), split_view_controller2->left_window());
7425 EXPECT_EQ(root_windows[1], window2->GetRootWindow());
7426 EXPECT_TRUE(InOverviewSession());
7427 }
7428
7429 // Verify that window resizing performance is recorded to the correct histogram
7430 // depending on whether the overview grid is empty.
TEST_P(SplitViewOverviewSessionInClamshellTestMultiDisplayOnly,WindowResizingPerformanceHistogramsTest)7431 TEST_P(SplitViewOverviewSessionInClamshellTestMultiDisplayOnly,
7432 WindowResizingPerformanceHistogramsTest) {
7433 UpdateDisplay("800x600,800x600");
7434 aura::Window::Windows root_windows = Shell::GetAllRootWindows();
7435 ASSERT_EQ(2u, root_windows.size());
7436 const gfx::Rect bounds_within_root1(0, 0, 400, 400);
7437 const gfx::Rect bounds_within_root2(800, 0, 400, 400);
7438 std::unique_ptr<aura::Window> window1(
7439 CreateWindowWithHitTestComponent(HTRIGHT, bounds_within_root1));
7440 std::unique_ptr<aura::Window> window2(
7441 CreateWindowWithHitTestComponent(HTRIGHT, bounds_within_root2));
7442 std::unique_ptr<aura::Window> window3 = CreateTestWindow(bounds_within_root2);
7443 ToggleOverview();
7444 SplitViewController::Get(root_windows[0])
7445 ->SnapWindow(window1.get(), SplitViewController::LEFT);
7446 SplitViewController::Get(root_windows[1])
7447 ->SnapWindow(window2.get(), SplitViewController::LEFT);
7448 // Resize |window1|, which is in split view with an empty overview grid.
7449 ui::test::EventGenerator generator1(root_windows[0], window1.get());
7450 generator1.PressLeftButton();
7451 CheckWindowResizingPerformanceHistograms("BeforeResizingWindow1", 0, 0, 0, 0);
7452 generator1.MoveMouseBy(50, 50);
7453 CheckWindowResizingPerformanceHistograms("WhileResizingWindow1", 1, 0, 0, 0);
7454 generator1.ReleaseLeftButton();
7455 CheckWindowResizingPerformanceHistograms("AfterResizingWindow1", 1, 1, 0, 0);
7456 // Resize |window2|, which is in split view with a nonempty overview grid.
7457 Shell::Get()->cursor_manager()->SetDisplay(
7458 display::Screen::GetScreen()->GetDisplayNearestWindow(root_windows[1]));
7459 ui::test::EventGenerator generator2(root_windows[1], window2.get());
7460 generator2.PressLeftButton();
7461 CheckWindowResizingPerformanceHistograms("BeforeResizingWindow2", 1, 1, 0, 0);
7462 generator2.MoveMouseBy(50, 50);
7463 CheckWindowResizingPerformanceHistograms("WhileResizingWindow2", 1, 1, 1, 0);
7464 generator2.ReleaseLeftButton();
7465 CheckWindowResizingPerformanceHistograms("AfterResizingWindow2", 1, 1, 1, 1);
7466 }
7467
7468 // Verify that the user action "SplitView_MultiDisplaySplitView" is recorded
7469 // when multi-display split view starts, and that a value is recorded to the
7470 // histogram "Ash.SplitView.TimeInMultiDisplaySplitView" when multi-display
7471 // split view ends. This test does not actually examine the timing values
7472 // recorded to the histogram, but this test does provide evidence of timing
7473 // accuracy as the time in multi-display split view is measured from the time
7474 // when the user action "SplitView_MultiDisplaySplitView" is recorded.
TEST_P(SplitViewOverviewSessionInClamshellTestMultiDisplayOnly,MultiDisplaySplitViewMetrics)7475 TEST_P(SplitViewOverviewSessionInClamshellTestMultiDisplayOnly,
7476 MultiDisplaySplitViewMetrics) {
7477 base::UserActionTester user_action_tester;
7478 base::HistogramTester histogram_tester;
7479 // Verifies that multi-display split view has started exactly |start_count|
7480 // times and ended exactly |end_count| times. If not, then the output will
7481 // include |description| to indicate where the test failed.
7482 const auto verify = [&user_action_tester, &histogram_tester](
7483 const char* description, int start_count,
7484 int end_count) {
7485 SCOPED_TRACE(description);
7486 EXPECT_EQ(start_count, user_action_tester.GetActionCount(
7487 "SplitView_MultiDisplaySplitView"));
7488 histogram_tester.ExpectTotalCount(
7489 "Ash.SplitView.TimeInMultiDisplaySplitView", end_count);
7490 };
7491
7492 UpdateDisplay("800x600,800x600,800x600");
7493 aura::Window::Windows root_windows = Shell::GetAllRootWindows();
7494 ASSERT_EQ(3u, root_windows.size());
7495 const gfx::Rect bounds_within_root1(0, 0, 400, 400);
7496 const gfx::Rect bounds_within_root2(800, 0, 400, 400);
7497 const gfx::Rect bounds_within_root3(1600, 0, 400, 400);
7498 std::unique_ptr<aura::Window> window1 = CreateTestWindow(bounds_within_root1);
7499 std::unique_ptr<aura::Window> window2 = CreateTestWindow(bounds_within_root1);
7500 std::unique_ptr<aura::Window> window3 = CreateTestWindow(bounds_within_root2);
7501 std::unique_ptr<aura::Window> window4 = CreateTestWindow(bounds_within_root2);
7502 std::unique_ptr<aura::Window> window5 = CreateTestWindow(bounds_within_root3);
7503 SplitViewController* split_view_controller1 =
7504 SplitViewController::Get(root_windows[0]);
7505 SplitViewController* split_view_controller2 =
7506 SplitViewController::Get(root_windows[1]);
7507 SplitViewController* split_view_controller3 =
7508 SplitViewController::Get(root_windows[2]);
7509 verify("1. Unit test set up", 0, 0);
7510 ToggleOverview();
7511 split_view_controller1->SnapWindow(window1.get(), SplitViewController::LEFT);
7512 verify("2. Number of displays in split view changed from 0 to 1", 0, 0);
7513 split_view_controller2->SnapWindow(window3.get(), SplitViewController::LEFT);
7514 verify("3. Number of displays in split view changed from 1 to 2", 1, 0);
7515 ToggleOverview();
7516 verify("4. Number of displays in split view changed from 2 to 0", 1, 1);
7517 ToggleOverview();
7518 split_view_controller1->SnapWindow(window1.get(), SplitViewController::LEFT);
7519 verify("5. Number of displays in split view changed from 0 to 1", 1, 1);
7520 split_view_controller2->SnapWindow(window3.get(), SplitViewController::LEFT);
7521 verify("6. Number of displays in split view changed from 1 to 2", 2, 1);
7522 split_view_controller3->SnapWindow(window5.get(), SplitViewController::LEFT);
7523 verify("7. Number of displays in split view changed from 2 to 3", 2, 1);
7524 ToggleOverview();
7525 verify("8. Number of displays in split view changed from 3 to 0", 2, 2);
7526 ToggleOverview();
7527 split_view_controller1->SnapWindow(window1.get(), SplitViewController::LEFT);
7528 verify("9. Number of displays in split view changed from 0 to 1", 2, 2);
7529 split_view_controller2->SnapWindow(window3.get(), SplitViewController::LEFT);
7530 verify("10. Number of displays in split view changed from 1 to 2", 3, 2);
7531 split_view_controller3->SnapWindow(window5.get(), SplitViewController::LEFT);
7532 verify("11. Number of displays in split view changed from 2 to 3", 3, 2);
7533 // For good test coverage, after multi-display split view started with
7534 // |split_view_controller2|, now we end split view on |split_view_controller2|
7535 // first, and then end multi-display split view with |split_view_controller3|.
7536 window3.reset();
7537 verify("12. Number of displays in split view changed from 3 to 2", 3, 2);
7538 window5.reset();
7539 verify("13. Number of displays in split view changed from 2 to 1", 3, 3);
7540 window1.reset();
7541 verify("14. Number of displays in split view changed from 1 to 0", 3, 3);
7542 split_view_controller1->SnapWindow(window2.get(), SplitViewController::LEFT);
7543 verify("15. Number of displays in split view changed from 0 to 1", 3, 3);
7544 // In this case, multi-display split view ends as soon as it starts. The
7545 // metrics should report that as starting and ending multi-display split view.
7546 split_view_controller2->SnapWindow(window4.get(), SplitViewController::LEFT);
7547 verify(
7548 "16. Multi-display split view started by snapping last overview window",
7549 4, 4);
7550 }
7551
7552 // Verify that |SplitViewController::CanSnapWindow| checks that the minimum size
7553 // of the window fits into the left or top, with the default divider position.
7554 // (If the work area length is odd, then the right or bottom will be one pixel
7555 // larger.)
TEST_P(SplitViewOverviewSessionInClamshellTestMultiDisplayOnly,SnapWindowWithMinimumSizeTest)7556 TEST_P(SplitViewOverviewSessionInClamshellTestMultiDisplayOnly,
7557 SnapWindowWithMinimumSizeTest) {
7558 // The divider is 8 thick. For the default divider position, the remaining 792
7559 // of the work area on the first root window is divided into 396 on each side,
7560 // and the remaining 791 of the work area on the second root window is divided
7561 // into 395 on the left and 396 on the right (the left side is what matters).
7562 UpdateDisplay("800x600,799x600");
7563 aura::Window::Windows root_windows = Shell::GetAllRootWindows();
7564 ASSERT_EQ(2u, root_windows.size());
7565 const gfx::Rect bounds_within_root1(0, 0, 400, 400);
7566 const gfx::Rect bounds_within_root2(800, 0, 400, 400);
7567 // It should make no difference which root window has the window passed to
7568 // |SplitViewController::CanSnapWindow|. What should matter is the root window
7569 // of the |SplitViewController|. To verify, we test with |bounds_within_root1|
7570 // and |bounds_within_root2|, and expect the same results.
7571 for (const gfx::Rect& bounds : {bounds_within_root1, bounds_within_root2}) {
7572 SCOPED_TRACE(bounds.ToString());
7573 aura::test::TestWindowDelegate* delegate =
7574 aura::test::TestWindowDelegate::CreateSelfDestroyingDelegate();
7575 std::unique_ptr<aura::Window> window(
7576 CreateTestWindowInShellWithDelegate(delegate, /*id=*/-1, bounds));
7577 // Before setting a minimum size, expect that |window| can be snapped in
7578 // split view on either root window.
7579 EXPECT_TRUE(
7580 SplitViewController::Get(root_windows[0])->CanSnapWindow(window.get()));
7581 EXPECT_TRUE(
7582 SplitViewController::Get(root_windows[1])->CanSnapWindow(window.get()));
7583 // Either root window can accommodate a minimum size 395 wide.
7584 delegate->set_minimum_size(gfx::Size(395, 0));
7585 EXPECT_TRUE(
7586 SplitViewController::Get(root_windows[0])->CanSnapWindow(window.get()));
7587 EXPECT_TRUE(
7588 SplitViewController::Get(root_windows[1])->CanSnapWindow(window.get()));
7589 // Only the first root window can accommodate a minimum size 396 wide.
7590 delegate->set_minimum_size(gfx::Size(396, 0));
7591 EXPECT_TRUE(
7592 SplitViewController::Get(root_windows[0])->CanSnapWindow(window.get()));
7593 EXPECT_FALSE(
7594 SplitViewController::Get(root_windows[1])->CanSnapWindow(window.get()));
7595 // Neither root window can accommodate a minimum size 397 wide.
7596 delegate->set_minimum_size(gfx::Size(397, 0));
7597 EXPECT_FALSE(
7598 SplitViewController::Get(root_windows[0])->CanSnapWindow(window.get()));
7599 EXPECT_FALSE(
7600 SplitViewController::Get(root_windows[1])->CanSnapWindow(window.get()));
7601 }
7602 }
7603
7604 // Verify that when in overview mode, the selector items unsnappable indicator
7605 // shows up when expected.
TEST_P(SplitViewOverviewSessionInClamshellTestMultiDisplayOnly,OverviewUnsnappableIndicatorVisibility)7606 TEST_P(SplitViewOverviewSessionInClamshellTestMultiDisplayOnly,
7607 OverviewUnsnappableIndicatorVisibility) {
7608 UpdateDisplay("800x600,800x600");
7609 aura::Window::Windows root_windows = Shell::GetAllRootWindows();
7610 ASSERT_EQ(2u, root_windows.size());
7611 const gfx::Rect bounds_within_root1(0, 0, 400, 400);
7612 const gfx::Rect bounds_within_root2(800, 0, 400, 400);
7613 std::unique_ptr<aura::Window> window1 = CreateTestWindow(bounds_within_root1);
7614 std::unique_ptr<aura::Window> window2 = CreateTestWindow(bounds_within_root1);
7615 std::unique_ptr<aura::Window> window3 =
7616 CreateUnsnappableWindow(bounds_within_root1);
7617 std::unique_ptr<aura::Window> window4 = CreateTestWindow(bounds_within_root2);
7618 std::unique_ptr<aura::Window> window5 = CreateTestWindow(bounds_within_root2);
7619 std::unique_ptr<aura::Window> window6 =
7620 CreateUnsnappableWindow(bounds_within_root2);
7621 ToggleOverview();
7622 OverviewItem* item2 = GetOverviewItemForWindow(window2.get());
7623 OverviewItem* item3 = GetOverviewItemForWindow(window3.get());
7624 OverviewItem* item5 = GetOverviewItemForWindow(window5.get());
7625 OverviewItem* item6 = GetOverviewItemForWindow(window6.get());
7626
7627 // Note: |cannot_snap_label_view_| and its parent will be created on demand.
7628 ASSERT_FALSE(SplitViewController::Get(root_windows[0])->InSplitViewMode());
7629 ASSERT_FALSE(SplitViewController::Get(root_windows[1])->InSplitViewMode());
7630 EXPECT_FALSE(item2->cannot_snap_widget_for_testing());
7631 EXPECT_FALSE(item3->cannot_snap_widget_for_testing());
7632 EXPECT_FALSE(item5->cannot_snap_widget_for_testing());
7633 EXPECT_FALSE(item6->cannot_snap_widget_for_testing());
7634
7635 SplitViewController::Get(root_windows[0])
7636 ->SnapWindow(window1.get(), SplitViewController::LEFT);
7637 ASSERT_TRUE(SplitViewController::Get(root_windows[0])->InSplitViewMode());
7638 ASSERT_FALSE(SplitViewController::Get(root_windows[1])->InSplitViewMode());
7639 EXPECT_FALSE(item2->cannot_snap_widget_for_testing());
7640 ASSERT_TRUE(item3->cannot_snap_widget_for_testing());
7641 ui::Layer* item3_unsnappable_layer =
7642 item3->cannot_snap_widget_for_testing()->GetNativeWindow()->layer();
7643 EXPECT_EQ(1.f, item3_unsnappable_layer->opacity());
7644 EXPECT_FALSE(item5->cannot_snap_widget_for_testing());
7645 EXPECT_FALSE(item6->cannot_snap_widget_for_testing());
7646
7647 SplitViewController::Get(root_windows[1])
7648 ->SnapWindow(window4.get(), SplitViewController::LEFT);
7649 ASSERT_TRUE(SplitViewController::Get(root_windows[0])->InSplitViewMode());
7650 ASSERT_TRUE(SplitViewController::Get(root_windows[1])->InSplitViewMode());
7651 EXPECT_FALSE(item2->cannot_snap_widget_for_testing());
7652 EXPECT_EQ(1.f, item3_unsnappable_layer->opacity());
7653 EXPECT_FALSE(item5->cannot_snap_widget_for_testing());
7654 ASSERT_TRUE(item6->cannot_snap_widget_for_testing());
7655 ui::Layer* item6_unsnappable_layer =
7656 item6->cannot_snap_widget_for_testing()->GetNativeWindow()->layer();
7657 EXPECT_EQ(1.f, item6_unsnappable_layer->opacity());
7658
7659 SplitViewController::Get(root_windows[0])->EndSplitView();
7660 ASSERT_FALSE(SplitViewController::Get(root_windows[0])->InSplitViewMode());
7661 ASSERT_TRUE(SplitViewController::Get(root_windows[1])->InSplitViewMode());
7662 EXPECT_FALSE(item2->cannot_snap_widget_for_testing());
7663 EXPECT_EQ(0.f, item3_unsnappable_layer->opacity());
7664 EXPECT_FALSE(item5->cannot_snap_widget_for_testing());
7665 EXPECT_EQ(1.f, item6_unsnappable_layer->opacity());
7666
7667 SplitViewController::Get(root_windows[1])->EndSplitView();
7668 ASSERT_FALSE(SplitViewController::Get(root_windows[0])->InSplitViewMode());
7669 ASSERT_FALSE(SplitViewController::Get(root_windows[1])->InSplitViewMode());
7670 EXPECT_FALSE(item2->cannot_snap_widget_for_testing());
7671 EXPECT_EQ(0.f, item3_unsnappable_layer->opacity());
7672 EXPECT_FALSE(item5->cannot_snap_widget_for_testing());
7673 EXPECT_EQ(0.f, item6_unsnappable_layer->opacity());
7674 }
7675
7676 // Test that enabling the docked magnifier ends clamshell split view on all
7677 // displays.
TEST_P(SplitViewOverviewSessionInClamshellTestMultiDisplayOnly,DockedMagnifierEndsClamshellSplitView)7678 TEST_P(SplitViewOverviewSessionInClamshellTestMultiDisplayOnly,
7679 DockedMagnifierEndsClamshellSplitView) {
7680 UpdateDisplay("800x600,800x600");
7681 aura::Window::Windows root_windows = Shell::GetAllRootWindows();
7682 ASSERT_EQ(2u, root_windows.size());
7683 const gfx::Rect bounds_within_root1(0, 0, 400, 400);
7684 const gfx::Rect bounds_within_root2(800, 0, 400, 400);
7685 std::unique_ptr<aura::Window> window1 = CreateTestWindow(bounds_within_root1);
7686 std::unique_ptr<aura::Window> window2 = CreateTestWindow(bounds_within_root1);
7687 std::unique_ptr<aura::Window> window3 = CreateTestWindow(bounds_within_root2);
7688 ToggleOverview();
7689 SplitViewController::Get(root_windows[0])
7690 ->SnapWindow(window1.get(), SplitViewController::LEFT);
7691 SplitViewController::Get(root_windows[1])
7692 ->SnapWindow(window3.get(), SplitViewController::LEFT);
7693 EXPECT_TRUE(InOverviewSession());
7694 EXPECT_TRUE(SplitViewController::Get(root_windows[0])->InSplitViewMode());
7695 EXPECT_TRUE(SplitViewController::Get(root_windows[1])->InSplitViewMode());
7696 Shell::Get()->docked_magnifier_controller()->SetEnabled(true);
7697 EXPECT_FALSE(InOverviewSession());
7698 EXPECT_FALSE(SplitViewController::Get(root_windows[0])->InSplitViewMode());
7699 EXPECT_FALSE(SplitViewController::Get(root_windows[1])->InSplitViewMode());
7700 }
7701
7702 INSTANTIATE_TEST_SUITE_P(All, OverviewSessionTest, testing::Bool());
7703 INSTANTIATE_TEST_SUITE_P(All, TabletModeOverviewSessionTest, testing::Bool());
7704 INSTANTIATE_TEST_SUITE_P(All, SplitViewOverviewSessionTest, testing::Bool());
7705 INSTANTIATE_TEST_SUITE_P(All,
7706 SplitViewOverviewSessionInClamshellTest,
7707 testing::Bool());
7708 INSTANTIATE_TEST_SUITE_P(
7709 All,
7710 SplitViewOverviewSessionInClamshellTestMultiDisplayOnly,
7711 testing::Values(true));
7712
7713 } // namespace ash
7714