Commit bba82810 authored by Eliot Courtney's avatar Eliot Courtney Committed by Commit Bot

Fix misc PIP multi-display bugs and refactor tests.

This change fixes some errors in conversions between Screen and root
window coordinates. It also makes the PIP window layout tests run for
multiple display configurations.

Test: unit test
Bug: b/124689893
Change-Id: I764c48d951e36c2b4bcf1d4334bf0b36a4966e64
Reviewed-on: https://chromium-review.googlesource.com/c/1477463
Commit-Queue: Eliot Courtney <edcourtney@chromium.org>
Reviewed-by: default avatarMitsuru Oshima (Slow) <oshima@chromium.org>
Cr-Commit-Position: refs/heads/master@{#636336}
parent 33da2308
......@@ -16,6 +16,7 @@
#include "ui/aura/window.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/keyboard/keyboard_controller.h"
#include "ui/wm/core/coordinate_conversion.h"
namespace ash {
......@@ -87,6 +88,7 @@ std::vector<gfx::Rect> CollectCollisionRects(const display::Display& display) {
continue;
// Use the target bounds in case an animation is in progress.
rects.push_back(window->GetTargetBounds());
::wm::ConvertRectToScreen(root_window, &rects.back());
rects.back().Inset(-kPipWorkAreaInsetsDp, -kPipWorkAreaInsetsDp);
}
}
......@@ -98,6 +100,7 @@ std::vector<gfx::Rect> CollectCollisionRects(const display::Display& display) {
keyboard_controller->GetRootWindow() == root_window &&
!keyboard_controller->visual_bounds_in_screen().IsEmpty()) {
rects.push_back(keyboard_controller->visual_bounds_in_screen());
::wm::ConvertRectToScreen(root_window, &rects.back());
rects.back().Inset(-kPipWorkAreaInsetsDp, -kPipWorkAreaInsetsDp);
}
......@@ -186,13 +189,15 @@ gfx::Point ComputeBestCandidatePoint(const gfx::Point& center,
gfx::Rect PipPositioner::GetMovementArea(const display::Display& display) {
gfx::Rect work_area = display.work_area();
auto* keyboard_controller = keyboard::KeyboardController::Get();
// Include keyboard if it's not floating.
auto* keyboard_controller = keyboard::KeyboardController::Get();
if (keyboard_controller->IsEnabled() &&
keyboard_controller->GetActiveContainerType() !=
keyboard::mojom::ContainerType::kFloating) {
gfx::Rect keyboard_bounds = keyboard_controller->visual_bounds_in_screen();
::wm::ConvertRectToScreen(Shell::GetRootWindowForDisplayId(display.id()),
&keyboard_bounds);
work_area.Subtract(keyboard_bounds);
}
......@@ -201,16 +206,16 @@ gfx::Rect PipPositioner::GetMovementArea(const display::Display& display) {
}
gfx::Rect PipPositioner::GetBoundsForDrag(const display::Display& display,
const gfx::Rect& bounds) {
gfx::Rect drag_bounds = bounds;
const gfx::Rect& bounds_in_screen) {
gfx::Rect drag_bounds = bounds_in_screen;
drag_bounds.AdjustToFit(GetMovementArea(display));
drag_bounds = AvoidObstacles(display, drag_bounds);
return drag_bounds;
}
gfx::Rect PipPositioner::GetRestingPosition(const display::Display& display,
const gfx::Rect& bounds) {
gfx::Rect resting_bounds = bounds;
const gfx::Rect& bounds_in_screen) {
gfx::Rect resting_bounds = bounds_in_screen;
gfx::Rect area = GetMovementArea(display);
resting_bounds.AdjustToFit(area);
......@@ -219,21 +224,24 @@ gfx::Rect PipPositioner::GetRestingPosition(const display::Display& display,
return AvoidObstacles(display, resting_bounds);
}
gfx::Rect PipPositioner::GetDismissedPosition(const display::Display& display,
const gfx::Rect& bounds) {
gfx::Rect PipPositioner::GetDismissedPosition(
const display::Display& display,
const gfx::Rect& bounds_in_screen) {
gfx::Rect work_area = GetMovementArea(display);
const int gravity = GetGravityToClosestEdge(bounds, work_area);
const int gravity = GetGravityToClosestEdge(bounds_in_screen, work_area);
// Allow the bounds to move at most |kPipDismissMovementProportion| of the
// length of the bounds in the direction of movement.
gfx::Rect bounds_movement_area = bounds;
bounds_movement_area.Inset(-bounds.width() * kPipDismissMovementProportion,
-bounds.height() * kPipDismissMovementProportion);
gfx::Rect dismissed_bounds =
GetAdjustedBoundsByGravity(bounds, bounds_movement_area, gravity);
gfx::Rect bounds_movement_area = bounds_in_screen;
bounds_movement_area.Inset(
-bounds_in_screen.width() * kPipDismissMovementProportion,
-bounds_in_screen.height() * kPipDismissMovementProportion);
gfx::Rect dismissed_bounds = GetAdjustedBoundsByGravity(
bounds_in_screen, bounds_movement_area, gravity);
// If the PIP window isn't close enough to the edge of the screen, don't slide
// it out.
return work_area.Intersects(dismissed_bounds) ? bounds : dismissed_bounds;
return work_area.Intersects(dismissed_bounds) ? bounds_in_screen
: dismissed_bounds;
}
gfx::Rect PipPositioner::GetPositionAfterMovementAreaChange(
......@@ -241,14 +249,15 @@ gfx::Rect PipPositioner::GetPositionAfterMovementAreaChange(
// Restore to previous bounds if we have them. This lets us move the PIP
// window back to its original bounds after transient movement area changes,
// like the keyboard popping up and pushing the PIP window up.
const gfx::Rect bounds = window_state->HasRestoreBounds()
? window_state->GetRestoreBoundsInScreen()
: window_state->window()->GetBoundsInScreen();
return GetRestingPosition(window_state->GetDisplay(), bounds);
const gfx::Rect bounds_in_screen =
window_state->HasRestoreBounds()
? window_state->GetRestoreBoundsInScreen()
: window_state->window()->GetBoundsInScreen();
return GetRestingPosition(window_state->GetDisplay(), bounds_in_screen);
}
gfx::Rect PipPositioner::AvoidObstacles(const display::Display& display,
const gfx::Rect& bounds) {
const gfx::Rect& bounds_in_screen) {
gfx::Rect work_area = GetMovementArea(display);
auto rects = CollectCollisionRects(display);
// The worst case for this should be: floating keyboard + one system tray +
......@@ -257,32 +266,34 @@ gfx::Rect PipPositioner::AvoidObstacles(const display::Display& display,
"should be optimized if there are a lot of "
"windows. Please see crrev.com/c/1221427 for a "
"description of an N^2 algorithm.";
return AvoidObstaclesInternal(work_area, rects, bounds);
return AvoidObstaclesInternal(work_area, rects, bounds_in_screen);
}
gfx::Rect PipPositioner::AvoidObstaclesInternal(
const gfx::Rect& work_area,
const std::vector<gfx::Rect>& rects,
const gfx::Rect& bounds) {
const gfx::Rect& bounds_in_screen) {
gfx::Rect inset_work_area = work_area;
// For even sized bounds, there is no 'center' integer point, so we need
// to adjust the obstacles and work area to account for this.
inset_work_area.Inset(bounds.width() / 2, bounds.height() / 2,
(bounds.width() - 1) / 2, (bounds.height() - 1) / 2);
inset_work_area.Inset(
bounds_in_screen.width() / 2, bounds_in_screen.height() / 2,
(bounds_in_screen.width() - 1) / 2, (bounds_in_screen.height() - 1) / 2);
std::vector<gfx::Rect> inset_rects(rects);
for (auto& rect : inset_rects) {
// Reduce the collision resolution problem from rectangles-rectangle
// resolution to rectangles-point resolution, by expanding each obstacle
// by |bounds| size.
rect.Inset(-(bounds.width() - 1) / 2, -(bounds.height() - 1) / 2,
-bounds.width() / 2, -bounds.height() / 2);
// by |bounds_in_screen| size.
rect.Inset(-(bounds_in_screen.width() - 1) / 2,
-(bounds_in_screen.height() - 1) / 2,
-bounds_in_screen.width() / 2, -bounds_in_screen.height() / 2);
}
gfx::Point moved_center = ComputeBestCandidatePoint(
bounds.CenterPoint(), inset_work_area, inset_rects);
gfx::Rect moved_bounds = bounds;
moved_bounds.Offset(moved_center - bounds.CenterPoint());
bounds_in_screen.CenterPoint(), inset_work_area, inset_rects);
gfx::Rect moved_bounds = bounds_in_screen;
moved_bounds.Offset(moved_center - bounds_in_screen.CenterPoint());
return moved_bounds;
}
......
......@@ -19,8 +19,8 @@ namespace wm {
class WindowState;
} // namespace wm
class PipPositionerTest;
// Computes resting and dragging positions for PIP windows. Note that this
// class uses only Screen coordinates.
class ASH_EXPORT PipPositioner {
public:
static const int kPipDismissTimeMs = 300;
......@@ -36,20 +36,19 @@ class ASH_EXPORT PipPositioner {
// this will be at a screen edge, not in the middle of the screen.
// TODO(edcourtney): This should consider drag velocity for fling as well.
static gfx::Rect GetRestingPosition(const display::Display& display,
const gfx::Rect& bounds);
const gfx::Rect& bounds_in_screen);
// Adjusts bounds during a drag of a PIP window. For example, this will
// ensure that the PIP window cannot leave the PIP movement area.
// |bounds| is in screen coordinates.
static gfx::Rect GetBoundsForDrag(const display::Display& display,
const gfx::Rect& bounds);
const gfx::Rect& bounds_in_screen);
// Based on the current PIP window position, finds a final location of where
// the PIP window should be animated to to show a dismissal off the side
// of the screen. Note that this may return somewhere not off-screen if
// animating the PIP window off-screen would travel too far.
static gfx::Rect GetDismissedPosition(const display::Display& display,
const gfx::Rect& bounds);
const gfx::Rect& bounds_in_screen);
// Gets the position the PIP window should be moved to after a movement area
// change. For example, if the shelf is changed from auto-hidden to always
......@@ -58,12 +57,13 @@ class ASH_EXPORT PipPositioner {
wm::WindowState* window_state);
private:
friend class PipPositionerTest;
friend class PipPositionerDisplayTest;
friend class PipPositionerLogicTest;
// Moves |bounds| such that it does not intersect with system ui areas, such
// as the unified system tray or the floating keyboard.
static gfx::Rect AvoidObstacles(const display::Display& display,
const gfx::Rect& bounds);
const gfx::Rect& bounds_in_screen);
// Internal method for collision resolution. Returns a gfx::Rect with the
// same size as |bounds|. That rectangle will not intersect any of the
......@@ -72,7 +72,7 @@ class ASH_EXPORT PipPositioner {
// closest such rectangle to |bounds|.
static gfx::Rect AvoidObstaclesInternal(const gfx::Rect& work_area,
const std::vector<gfx::Rect>& rects,
const gfx::Rect& bounds);
const gfx::Rect& bounds_in_screen);
DISALLOW_COPY_AND_ASSIGN(PipPositioner);
};
......
......@@ -6,8 +6,13 @@
#include <memory>
#include <string>
#include <tuple>
#include <vector>
#include "ash/root_window_controller.h"
#include "ash/scoped_root_window_for_new_windows.h"
#include "ash/shelf/shelf.h"
#include "ash/shelf/shelf_layout_manager.h"
#include "ash/shell.h"
#include "ash/system/unified/unified_system_tray.h"
#include "ash/test/ash_test_base.h"
......@@ -20,39 +25,72 @@
#include "ui/keyboard/keyboard_controller.h"
#include "ui/keyboard/public/keyboard_switches.h"
#include "ui/keyboard/test/keyboard_test_util.h"
#include "ui/wm/core/coordinate_conversion.h"
namespace ash {
namespace {
// WindowState based on a given initial state.
class FakeWindowState : public wm::WindowState::State {
public:
explicit FakeWindowState(mojom::WindowStateType initial_state_type)
: state_type_(initial_state_type) {}
~FakeWindowState() override = default;
// WindowState::State overrides:
void OnWMEvent(wm::WindowState* window_state,
const wm::WMEvent* event) override {}
mojom::WindowStateType GetType() const override { return state_type_; }
void AttachState(wm::WindowState* window_state,
wm::WindowState::State* previous_state) override {}
void DetachState(wm::WindowState* window_state) override {}
display::Display GetDisplayForWindow(aura::Window* window) {
return display::Screen::GetScreen()->GetDisplayNearestWindow(window);
}
private:
mojom::WindowStateType state_type_;
gfx::Rect ConvertToScreenForWindow(aura::Window* window,
const gfx::Rect& bounds) {
gfx::Rect new_bounds = bounds;
::wm::ConvertRectToScreen(window->GetRootWindow(), &new_bounds);
return new_bounds;
}
DISALLOW_COPY_AND_ASSIGN(FakeWindowState);
};
void ForceHideShelves() {
for (auto* root_window_controller : Shell::GetAllRootWindowControllers()) {
auto* shelf = root_window_controller->shelf();
auto* layout_manager = shelf->shelf_layout_manager();
shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_ALWAYS_HIDDEN);
layout_manager->LayoutShelf(); // Force layout to end animation.
}
}
gfx::Rect ConvertPrimaryToScreen(const gfx::Rect& bounds) {
return ConvertToScreenForWindow(Shell::GetPrimaryRootWindow(), bounds);
}
} // namespace
class PipPositionerTest : public AshTestBase {
public:
PipPositionerTest() = default;
~PipPositionerTest() override = default;
using PipPositionerTest = AshTestBase;
TEST_F(PipPositionerTest,
PipRestingPositionSnapsInDisplayWithLargeAspectRatio) {
UpdateDisplay("1600x400");
// Snap to the top edge instead of the far left edge.
EXPECT_EQ(ConvertPrimaryToScreen(gfx::Rect(500, 8, 100, 100)),
PipPositioner::GetRestingPosition(
GetPrimaryDisplay(),
ConvertPrimaryToScreen(gfx::Rect(500, 100, 100, 100))));
}
TEST_F(PipPositionerTest, AvoidObstaclesAvoidsUnifiedSystemTray) {
UpdateDisplay("1000x1000");
auto* unified_system_tray = GetPrimaryUnifiedSystemTray();
unified_system_tray->ShowBubble(/*show_by_click=*/false);
auto display = GetPrimaryDisplay();
gfx::Rect area = PipPositioner::GetMovementArea(display);
gfx::Rect bubble_bounds = unified_system_tray->GetBubbleBoundsInScreen();
gfx::Rect bounds = gfx::Rect(bubble_bounds.x(), bubble_bounds.y(), 100, 100);
gfx::Rect moved_bounds = PipPositioner::GetRestingPosition(display, bounds);
// Expect that the returned bounds don't intersect the unified system tray
// but also don't leave the PIP movement area.
EXPECT_FALSE(moved_bounds.Intersects(bubble_bounds));
EXPECT_TRUE(area.Contains(moved_bounds));
}
class PipPositionerDisplayTest : public AshTestBase,
public ::testing::WithParamInterface<
std::tuple<std::string, std::size_t>> {
public:
void SetUp() override {
base::CommandLine::ForCurrentProcess()->AppendSwitch(
keyboard::switches::kEnableVirtualKeyboard);
......@@ -60,23 +98,25 @@ class PipPositionerTest : public AshTestBase {
SetTouchKeyboardEnabled(true);
Shell::Get()->EnableKeyboard();
UpdateWorkArea("400x400");
window_ = CreateTestWindowInShellWithBounds(gfx::Rect(200, 200, 100, 100));
wm::WindowState* window_state = wm::GetWindowState(window_);
test_state_ = new FakeWindowState(mojom::WindowStateType::PIP);
window_state->SetStateObject(
std::unique_ptr<wm::WindowState::State>(test_state_));
const std::string& display_string = std::get<0>(GetParam());
const std::size_t root_window_index = std::get<1>(GetParam());
UpdateWorkArea(display_string);
ASSERT_LT(root_window_index, Shell::GetAllRootWindows().size());
root_window_ = Shell::GetAllRootWindows()[root_window_index];
scoped_root_.reset(new ScopedRootWindowForNewWindows(root_window_));
}
void TearDown() override {
scoped_root_.reset();
SetTouchKeyboardEnabled(false);
AshTestBase::TearDown();
}
void UpdateWorkArea(const std::string& bounds) {
UpdateDisplay(bounds);
aura::Window* root = Shell::GetPrimaryRootWindow();
Shell::Get()->SetDisplayWorkAreaInsets(root, gfx::Insets());
protected:
display::Display GetDisplay() { return GetDisplayForWindow(root_window_); }
gfx::Rect ConvertToScreen(const gfx::Rect& bounds) {
return ConvertToScreenForWindow(root_window_, bounds);
}
gfx::Rect CallAvoidObstacles(const display::Display& display,
......@@ -84,219 +124,244 @@ class PipPositionerTest : public AshTestBase {
return PipPositioner::AvoidObstacles(display, bounds);
}
gfx::Rect CallAvoidObstaclesInternal(const gfx::Rect& work_area,
const std::vector<gfx::Rect>& rects,
const gfx::Rect& bounds) {
return PipPositioner::AvoidObstaclesInternal(work_area, rects, bounds);
// TODO dedpue?
void UpdateWorkArea(const std::string& bounds) {
UpdateDisplay(bounds);
for (aura::Window* root : Shell::GetAllRootWindows())
Shell::Get()->SetDisplayWorkAreaInsets(root, gfx::Insets());
}
protected:
aura::Window* window() { return window_; }
wm::WindowState* window_state() { return wm::GetWindowState(window_); }
FakeWindowState* test_state() { return test_state_; }
private:
aura::Window* window_;
FakeWindowState* test_state_;
DISALLOW_COPY_AND_ASSIGN(PipPositionerTest);
std::unique_ptr<ScopedRootWindowForNewWindows> scoped_root_;
aura::Window* root_window_;
};
TEST_F(PipPositionerTest, PipMovementAreaIsInset) {
gfx::Rect area = PipPositioner::GetMovementArea(window_state()->GetDisplay());
EXPECT_EQ(gfx::Rect(8, 8, 384, 384), area);
TEST_P(PipPositionerDisplayTest, PipMovementAreaIsInset) {
gfx::Rect area = PipPositioner::GetMovementArea(GetDisplay());
EXPECT_EQ(ConvertToScreen(gfx::Rect(8, 8, 384, 384)), area);
}
TEST_F(PipPositionerTest, PipMovementAreaIncludesKeyboardIfKeyboardIsShown) {
TEST_P(PipPositionerDisplayTest,
PipMovementAreaIncludesKeyboardIfKeyboardIsShown) {
auto* keyboard_controller = keyboard::KeyboardController::Get();
keyboard_controller->ShowKeyboard(/*lock=*/true);
keyboard_controller->ShowKeyboardInDisplay(GetDisplay());
ASSERT_TRUE(keyboard::WaitUntilShown());
aura::Window* keyboard_window = keyboard_controller->GetKeyboardWindow();
keyboard_window->SetBounds(gfx::Rect(0, 300, 400, 100));
ASSERT_TRUE(keyboard::WaitUntilShown());
gfx::Rect area = PipPositioner::GetMovementArea(window_state()->GetDisplay());
EXPECT_EQ(gfx::Rect(8, 8, 384, 284), area);
gfx::Rect area = PipPositioner::GetMovementArea(GetDisplay());
EXPECT_EQ(ConvertToScreen(gfx::Rect(8, 8, 384, 284)), area);
}
TEST_F(PipPositionerTest, PipRestingPositionSnapsToClosestEdge) {
auto display = window_state()->GetDisplay();
TEST_P(PipPositionerDisplayTest, PipRestingPositionSnapsToClosestEdge) {
auto display = GetDisplay();
// Snap near top edge to top.
EXPECT_EQ(
gfx::Rect(100, 8, 100, 100),
PipPositioner::GetRestingPosition(display, gfx::Rect(100, 50, 100, 100)));
EXPECT_EQ(ConvertToScreen(gfx::Rect(100, 8, 100, 100)),
PipPositioner::GetRestingPosition(
display, ConvertToScreen(gfx::Rect(100, 50, 100, 100))));
// Snap near bottom edge to bottom.
EXPECT_EQ(gfx::Rect(100, 292, 100, 100),
PipPositioner::GetRestingPosition(display,
gfx::Rect(100, 250, 100, 100)));
EXPECT_EQ(ConvertToScreen(gfx::Rect(100, 292, 100, 100)),
PipPositioner::GetRestingPosition(
display, ConvertToScreen(gfx::Rect(100, 250, 100, 100))));
// Snap near left edge to left.
EXPECT_EQ(
gfx::Rect(8, 100, 100, 100),
PipPositioner::GetRestingPosition(display, gfx::Rect(50, 100, 100, 100)));
EXPECT_EQ(ConvertToScreen(gfx::Rect(8, 100, 100, 100)),
PipPositioner::GetRestingPosition(
display, ConvertToScreen(gfx::Rect(50, 100, 100, 100))));
// Snap near right edge to right.
EXPECT_EQ(gfx::Rect(292, 100, 100, 100),
PipPositioner::GetRestingPosition(display,
gfx::Rect(250, 100, 100, 100)));
EXPECT_EQ(ConvertToScreen(gfx::Rect(292, 100, 100, 100)),
PipPositioner::GetRestingPosition(
display, ConvertToScreen(gfx::Rect(250, 100, 100, 100))));
}
TEST_F(PipPositionerTest, PipRestingPositionSnapsInsideDisplay) {
auto display = window_state()->GetDisplay();
TEST_P(PipPositionerDisplayTest, PipRestingPositionSnapsInsideDisplay) {
auto display = GetDisplay();
// Snap near top edge outside movement area to top.
EXPECT_EQ(gfx::Rect(100, 8, 100, 100),
PipPositioner::GetRestingPosition(display,
gfx::Rect(100, -50, 100, 100)));
EXPECT_EQ(ConvertToScreen(gfx::Rect(100, 8, 100, 100)),
PipPositioner::GetRestingPosition(
display, ConvertToScreen(gfx::Rect(100, -50, 100, 100))));
// Snap near bottom edge outside movement area to bottom.
EXPECT_EQ(gfx::Rect(100, 292, 100, 100),
PipPositioner::GetRestingPosition(display,
gfx::Rect(100, 450, 100, 100)));
EXPECT_EQ(ConvertToScreen(gfx::Rect(100, 292, 100, 100)),
PipPositioner::GetRestingPosition(
display, ConvertToScreen(gfx::Rect(100, 450, 100, 100))));
// Snap near left edge outside movement area to left.
EXPECT_EQ(gfx::Rect(8, 100, 100, 100),
PipPositioner::GetRestingPosition(display,
gfx::Rect(-50, 100, 100, 100)));
EXPECT_EQ(ConvertToScreen(gfx::Rect(8, 100, 100, 100)),
PipPositioner::GetRestingPosition(
display, ConvertToScreen(gfx::Rect(-50, 100, 100, 100))));
// Snap near right edge outside movement area to right.
EXPECT_EQ(gfx::Rect(292, 100, 100, 100),
PipPositioner::GetRestingPosition(display,
gfx::Rect(450, 100, 100, 100)));
EXPECT_EQ(ConvertToScreen(gfx::Rect(292, 100, 100, 100)),
PipPositioner::GetRestingPosition(
display, ConvertToScreen(gfx::Rect(450, 100, 100, 100))));
}
TEST_F(PipPositionerTest,
PipRestingPositionSnapsInDisplayWithLargeAspectRatio) {
UpdateDisplay("1600x400");
auto display = window_state()->GetDisplay();
// Snap to the top edge instead of the far left edge.
EXPECT_EQ(gfx::Rect(500, 8, 100, 100),
PipPositioner::GetRestingPosition(display,
gfx::Rect(500, 100, 100, 100)));
}
TEST_F(PipPositionerTest, PipAdjustPositionForDragClampsToMovementArea) {
auto display = window_state()->GetDisplay();
TEST_P(PipPositionerDisplayTest, PipAdjustPositionForDragClampsToMovementArea) {
auto display = GetDisplay();
// Adjust near top edge outside movement area.
EXPECT_EQ(
gfx::Rect(100, 8, 100, 100),
PipPositioner::GetBoundsForDrag(display, gfx::Rect(100, -50, 100, 100)));
EXPECT_EQ(ConvertToScreen(gfx::Rect(100, 8, 100, 100)),
PipPositioner::GetBoundsForDrag(
display, ConvertToScreen(gfx::Rect(100, -50, 100, 100))));
// Adjust near bottom edge outside movement area.
EXPECT_EQ(
gfx::Rect(100, 292, 100, 100),
PipPositioner::GetBoundsForDrag(display, gfx::Rect(100, 450, 100, 100)));
EXPECT_EQ(ConvertToScreen(gfx::Rect(100, 292, 100, 100)),
PipPositioner::GetBoundsForDrag(
display, ConvertToScreen(gfx::Rect(100, 450, 100, 100))));
// Adjust near left edge outside movement area.
EXPECT_EQ(
gfx::Rect(8, 100, 100, 100),
PipPositioner::GetBoundsForDrag(display, gfx::Rect(-50, 100, 100, 100)));
EXPECT_EQ(ConvertToScreen(gfx::Rect(8, 100, 100, 100)),
PipPositioner::GetBoundsForDrag(
display, ConvertToScreen(gfx::Rect(-50, 100, 100, 100))));
// Adjust near right edge outside movement area.
EXPECT_EQ(
gfx::Rect(292, 100, 100, 100),
PipPositioner::GetBoundsForDrag(display, gfx::Rect(450, 100, 100, 100)));
EXPECT_EQ(ConvertToScreen(gfx::Rect(292, 100, 100, 100)),
PipPositioner::GetBoundsForDrag(
display, ConvertToScreen(gfx::Rect(450, 100, 100, 100))));
}
TEST_F(PipPositionerTest, PipRestingPositionWorksIfKeyboardIsDisabled) {
TEST_P(PipPositionerDisplayTest, PipRestingPositionWorksIfKeyboardIsDisabled) {
Shell::Get()->DisableKeyboard();
auto display = window_state()->GetDisplay();
auto display = GetDisplay();
// Snap near top edge to top.
EXPECT_EQ(
gfx::Rect(100, 8, 100, 100),
PipPositioner::GetRestingPosition(display, gfx::Rect(100, 50, 100, 100)));
EXPECT_EQ(ConvertToScreen(gfx::Rect(100, 8, 100, 100)),
PipPositioner::GetRestingPosition(
display, ConvertToScreen(gfx::Rect(100, 50, 100, 100))));
}
TEST_F(PipPositionerTest, PipDismissedPositionDoesNotMoveAnExcessiveDistance) {
auto display = window_state()->GetDisplay();
TEST_P(PipPositionerDisplayTest,
PipDismissedPositionDoesNotMoveAnExcessiveDistance) {
auto display = GetDisplay();
EXPECT_EQ(gfx::Rect(100, 100, 100, 100),
PipPositioner::GetDismissedPosition(display,
gfx::Rect(100, 100, 100, 100)));
EXPECT_EQ(ConvertToScreen(gfx::Rect(100, 100, 100, 100)),
PipPositioner::GetDismissedPosition(
display, ConvertToScreen(gfx::Rect(100, 100, 100, 100))));
}
TEST_F(PipPositionerTest, PipDismissedPositionChosesClosestEdge) {
auto display = window_state()->GetDisplay();
TEST_P(PipPositionerDisplayTest, PipDismissedPositionChosesClosestEdge) {
auto display = GetDisplay();
// Dismiss near top edge outside movement area towards top.
EXPECT_EQ(gfx::Rect(100, -100, 100, 100),
PipPositioner::GetDismissedPosition(display,
gfx::Rect(100, 50, 100, 100)));
EXPECT_EQ(ConvertToScreen(gfx::Rect(100, -100, 100, 100)),
PipPositioner::GetDismissedPosition(
display, ConvertToScreen(gfx::Rect(100, 50, 100, 100))));
// Dismiss near bottom edge outside movement area towards bottom.
EXPECT_EQ(gfx::Rect(100, 400, 100, 100),
PipPositioner::GetDismissedPosition(display,
gfx::Rect(100, 250, 100, 100)));
EXPECT_EQ(ConvertToScreen(gfx::Rect(100, 400, 100, 100)),
PipPositioner::GetDismissedPosition(
display, ConvertToScreen(gfx::Rect(100, 250, 100, 100))));
// Dismiss near left edge outside movement area towards left.
EXPECT_EQ(gfx::Rect(-100, 100, 100, 100),
PipPositioner::GetDismissedPosition(display,
gfx::Rect(50, 100, 100, 100)));
EXPECT_EQ(ConvertToScreen(gfx::Rect(-100, 100, 100, 100)),
PipPositioner::GetDismissedPosition(
display, ConvertToScreen(gfx::Rect(50, 100, 100, 100))));
// Dismiss near right edge outside movement area towards right.
EXPECT_EQ(gfx::Rect(400, 100, 100, 100),
PipPositioner::GetDismissedPosition(display,
gfx::Rect(250, 100, 100, 100)));
EXPECT_EQ(ConvertToScreen(gfx::Rect(400, 100, 100, 100)),
PipPositioner::GetDismissedPosition(
display, ConvertToScreen(gfx::Rect(250, 100, 100, 100))));
}
// Verify that if two edges are equally close, the PIP window prefers dismissing
// out horizontally.
TEST_F(PipPositionerTest, PipDismissedPositionPrefersHorizontal) {
auto display = window_state()->GetDisplay();
TEST_P(PipPositionerDisplayTest, PipDismissedPositionPrefersHorizontal) {
auto display = GetDisplay();
// Top left corner.
EXPECT_EQ(
gfx::Rect(-150, 0, 100, 100),
PipPositioner::GetDismissedPosition(display, gfx::Rect(0, 0, 100, 100)));
EXPECT_EQ(ConvertToScreen(gfx::Rect(-150, 0, 100, 100)),
PipPositioner::GetDismissedPosition(
display, ConvertToScreen(gfx::Rect(0, 0, 100, 100))));
// Top right corner.
EXPECT_EQ(gfx::Rect(450, 0, 100, 100),
PipPositioner::GetDismissedPosition(display,
gfx::Rect(300, 0, 100, 100)));
EXPECT_EQ(ConvertToScreen(gfx::Rect(450, 0, 100, 100)),
PipPositioner::GetDismissedPosition(
display, ConvertToScreen(gfx::Rect(300, 0, 100, 100))));
// Bottom left corner.
EXPECT_EQ(gfx::Rect(-150, 300, 100, 100),
PipPositioner::GetDismissedPosition(display,
gfx::Rect(0, 300, 100, 100)));
EXPECT_EQ(ConvertToScreen(gfx::Rect(-150, 300, 100, 100)),
PipPositioner::GetDismissedPosition(
display, ConvertToScreen(gfx::Rect(0, 300, 100, 100))));
// Bottom right corner.
EXPECT_EQ(gfx::Rect(450, 300, 100, 100),
PipPositioner::GetDismissedPosition(display,
gfx::Rect(300, 300, 100, 100)));
EXPECT_EQ(ConvertToScreen(gfx::Rect(450, 300, 100, 100)),
PipPositioner::GetDismissedPosition(
display, ConvertToScreen(gfx::Rect(300, 300, 100, 100))));
}
TEST_F(PipPositionerTest,
PipRestoresToPreviousBoundsOnMovementAreaChangeIfTheyExist) {
// Position the PIP window on the side of the screen where it will be next
// to an edge and therefore in a resting position for the whole test.
const gfx::Rect bounds = gfx::Rect(292, 200, 100, 100);
// Set restore position to where the window currently is.
window()->SetBounds(bounds);
window_state()->SetRestoreBoundsInScreen(bounds);
EXPECT_TRUE(window_state()->HasRestoreBounds());
// Update the work area so that the PIP window should be pushed upward.
UpdateWorkArea("400x200");
// Set PIP to the updated constrained bounds.
const gfx::Rect constrained_bounds =
PipPositioner::GetPositionAfterMovementAreaChange(window_state());
EXPECT_EQ(gfx::Rect(292, 92, 100, 100), constrained_bounds);
window()->SetBounds(constrained_bounds);
// Restore the original work area.
UpdateWorkArea("400x400");
// Expect that the PIP window is put back to where it was before.
EXPECT_EQ(gfx::Rect(292, 200, 100, 100),
PipPositioner::GetPositionAfterMovementAreaChange(window_state()));
TEST_P(PipPositionerDisplayTest, AvoidObstaclesAvoidsFloatingKeyboard) {
auto display = GetDisplay();
auto* keyboard_controller = keyboard::KeyboardController::Get();
keyboard_controller->SetContainerType(
keyboard::mojom::ContainerType::kFloating, base::nullopt,
base::DoNothing());
keyboard_controller->ShowKeyboardInDisplay(display);
ASSERT_TRUE(keyboard::WaitUntilShown());
aura::Window* keyboard_window = keyboard_controller->GetKeyboardWindow();
keyboard_window->SetBounds(gfx::Rect(0, 0, 100, 100));
ForceHideShelves(); // Showing the keyboard may have shown the shelf.
gfx::Rect area = PipPositioner::GetMovementArea(display);
gfx::Rect moved_bounds =
CallAvoidObstacles(display, ConvertToScreen(gfx::Rect(8, 8, 100, 100)));
// Expect that the returned bounds don't intersect the floating keyboard
// but also don't leave the PIP movement area.
EXPECT_FALSE(moved_bounds.Intersects(keyboard_window->GetBoundsInScreen()));
EXPECT_TRUE(area.Contains(moved_bounds));
}
TEST_F(PipPositionerTest,
TEST_P(PipPositionerDisplayTest,
AvoidObstaclesDoesNotChangeBoundsIfThereIsNoCollision) {
auto display = GetDisplay();
EXPECT_EQ(ConvertToScreen(gfx::Rect(100, 100, 100, 100)),
CallAvoidObstacles(display,
ConvertToScreen(gfx::Rect(100, 100, 100, 100))));
}
TEST_P(PipPositionerDisplayTest, GetRestingPositionAvoidsKeyboard) {
auto display = GetDisplay();
auto* keyboard_controller = keyboard::KeyboardController::Get();
keyboard_controller->ShowKeyboardInDisplay(display);
ASSERT_TRUE(keyboard::WaitUntilShown());
aura::Window* keyboard_window = keyboard_controller->GetKeyboardWindow();
keyboard_window->SetBounds(gfx::Rect(0, 300, 400, 100));
EXPECT_EQ(ConvertToScreen(gfx::Rect(8, 192, 100, 100)),
PipPositioner::GetRestingPosition(
display, ConvertToScreen(gfx::Rect(8, 300, 100, 100))));
}
// TODO: UpdateDisplay() doesn't support different layouts of multiple displays.
// We should add some way to try multiple layouts.
INSTANTIATE_TEST_SUITE_P(
/* no prefix */,
PipPositionerDisplayTest,
testing::Values(std::make_tuple("400x400", 0u),
std::make_tuple("400x400/r", 0u),
std::make_tuple("400x400/u", 0u),
std::make_tuple("400x400/l", 0u),
std::make_tuple("800x800*2", 0u),
std::make_tuple("400x400,400x400", 0u),
std::make_tuple("400x400,400x400", 1u)));
class PipPositionerLogicTest : public ::testing::Test {
public:
gfx::Rect CallAvoidObstaclesInternal(const gfx::Rect& work_area,
const std::vector<gfx::Rect>& rects,
const gfx::Rect& bounds) {
return PipPositioner::AvoidObstaclesInternal(work_area, rects, bounds);
}
};
TEST_F(PipPositionerLogicTest,
AvoidObstaclesDoesNotMoveBoundsIfThereIsNoIntersection) {
const gfx::Rect area(0, 0, 400, 400);
......@@ -337,7 +402,7 @@ TEST_F(PipPositionerTest,
gfx::Rect(100, 300, 100, 100)));
}
TEST_F(PipPositionerTest, AvoidObstaclesOffByOneCases) {
TEST_F(PipPositionerLogicTest, AvoidObstaclesOffByOneCases) {
const gfx::Rect area(0, 0, 400, 400);
// Test 1x1 PIP window intersecting a 1x1 obstacle.
......@@ -465,7 +530,7 @@ TEST_F(PipPositionerTest, AvoidObstaclesOffByOneCases) {
gfx::Rect(9, 12, 3, 3)));
}
TEST_F(PipPositionerTest, AvoidObstaclesNestedObstacle) {
TEST_F(PipPositionerLogicTest, AvoidObstaclesNestedObstacle) {
const gfx::Rect area(0, 0, 400, 400);
EXPECT_EQ(gfx::Rect(9, 16, 1, 1),
CallAvoidObstaclesInternal(
......@@ -473,7 +538,7 @@ TEST_F(PipPositionerTest, AvoidObstaclesNestedObstacle) {
gfx::Rect(16, 16, 1, 1)));
}
TEST_F(PipPositionerTest, AvoidObstaclesAvoidsTwoObstacles) {
TEST_F(PipPositionerLogicTest, AvoidObstaclesAvoidsTwoObstacles) {
const gfx::Rect area(0, 0, 400, 400);
const std::vector<gfx::Rect> obstacles = {gfx::Rect(4, 1, 4, 5),
gfx::Rect(2, 4, 4, 5)};
......@@ -489,7 +554,7 @@ TEST_F(PipPositionerTest, AvoidObstaclesAvoidsTwoObstacles) {
CallAvoidObstaclesInternal(area, obstacles, gfx::Rect(4, 1, 2, 2)));
}
TEST_F(PipPositionerTest, AvoidObstaclesAvoidsThreeObstacles) {
TEST_F(PipPositionerLogicTest, AvoidObstaclesAvoidsThreeObstacles) {
const gfx::Rect area(0, 0, 400, 400);
const std::vector<gfx::Rect> obstacles = {
gfx::Rect(4, 1, 4, 5), gfx::Rect(2, 4, 4, 5), gfx::Rect(2, 1, 3, 4)};
......@@ -502,7 +567,8 @@ TEST_F(PipPositionerTest, AvoidObstaclesAvoidsThreeObstacles) {
CallAvoidObstaclesInternal(area, obstacles, gfx::Rect(3, 3, 2, 2)));
}
TEST_F(PipPositionerTest, AvoidObstaclesDoesNotPositionBoundsOutsideOfPipArea) {
TEST_F(PipPositionerLogicTest,
AvoidObstaclesDoesNotPositionBoundsOutsideOfPipArea) {
// Position the bounds such that moving it the least distance to stop
// intersecting |obstacle| would put it outside of |area|. It should go
// instead to the position of second least distance, which would be below
......@@ -514,7 +580,8 @@ TEST_F(PipPositionerTest, AvoidObstaclesDoesNotPositionBoundsOutsideOfPipArea) {
CallAvoidObstaclesInternal(area, {obstacle}, bounds));
}
TEST_F(PipPositionerTest, AvoidObstaclesPositionsBoundsWithLeastDisplacement) {
TEST_F(PipPositionerLogicTest,
AvoidObstaclesPositionsBoundsWithLeastDisplacement) {
const gfx::Rect area(0, 0, 400, 400);
const gfx::Rect obstacle(200, 200, 100, 100);
......@@ -539,70 +606,4 @@ TEST_F(PipPositionerTest, AvoidObstaclesPositionsBoundsWithLeastDisplacement) {
gfx::Rect(200, 150, 100, 100)));
}
TEST_F(PipPositionerTest, AvoidObstaclesAvoidsUnifiedSystemTray) {
UpdateDisplay("1000x1000");
auto* unified_system_tray = GetPrimaryUnifiedSystemTray();
unified_system_tray->ShowBubble(/*show_by_click=*/false);
auto display = window_state()->GetDisplay();
gfx::Rect area = PipPositioner::GetMovementArea(display);
gfx::Rect bubble_bounds = unified_system_tray->GetBubbleBoundsInScreen();
gfx::Rect bounds = gfx::Rect(bubble_bounds.x(), bubble_bounds.y(), 100, 100);
gfx::Rect moved_bounds = CallAvoidObstacles(display, bounds);
// Expect that the returned bounds don't intersect the unified system tray
// but also don't leave the PIP movement area.
EXPECT_FALSE(moved_bounds.Intersects(bubble_bounds));
EXPECT_TRUE(area.Contains(moved_bounds));
}
TEST_F(PipPositionerTest, AvoidObstaclesAvoidsFloatingKeyboard) {
auto* keyboard_controller = keyboard::KeyboardController::Get();
keyboard_controller->SetContainerType(
keyboard::mojom::ContainerType::kFloating, base::nullopt,
base::DoNothing());
keyboard_controller->ShowKeyboard(/*lock=*/true);
aura::Window* keyboard_window = keyboard_controller->GetKeyboardWindow();
keyboard_window->SetBounds(gfx::Rect(200, 200, 100, 100));
ASSERT_TRUE(keyboard::WaitUntilShown());
auto display = window_state()->GetDisplay();
gfx::Rect area = PipPositioner::GetMovementArea(display);
gfx::Rect moved_bounds =
CallAvoidObstacles(display, gfx::Rect(150, 200, 100, 100));
// Expect that the returned bounds don't intersect the floating keyboard
// but also don't leave the PIP movement area.
EXPECT_FALSE(moved_bounds.Intersects(keyboard_window->GetBoundsInScreen()));
EXPECT_TRUE(area.Contains(moved_bounds));
}
TEST_F(PipPositionerTest,
AvoidObstaclesDoesNotChangeBoundsIfThereIsNoCollision) {
auto display = window_state()->GetDisplay();
EXPECT_EQ(gfx::Rect(100, 100, 100, 100),
CallAvoidObstacles(display, gfx::Rect(100, 100, 100, 100)));
}
TEST_F(PipPositionerTest, PipInitailPositionAvoidsObstacles) {
// Place a keyboard window at the initial position of a PIP window.
auto* keyboard_controller = keyboard::KeyboardController::Get();
keyboard_controller->ShowKeyboard(/*lock=*/true);
aura::Window* keyboard_window = keyboard_controller->GetKeyboardWindow();
keyboard_window->SetBounds(gfx::Rect(0, 0, 400, 100));
ASSERT_TRUE(keyboard::WaitUntilShown());
std::unique_ptr<aura::Window> window(
CreateTestWindowInShellWithBounds(gfx::Rect(100, 100, 100, 100)));
wm::WindowState* window_state = wm::GetWindowState(window.get());
const wm::WMEvent enter_pip(wm::WM_EVENT_PIP);
window_state->OnWMEvent(&enter_pip);
EXPECT_TRUE(window_state->IsPip());
window->Show();
EXPECT_TRUE(window->layer()->visible());
// Ensure the initial PIP position is shifted below the keyboard.
EXPECT_EQ("8,100 100x100", window->layer()->GetTargetBounds().ToString());
}
} // namespace ash
......@@ -13,30 +13,53 @@
#include "ash/shell.h"
#include "ash/system/status_area_widget.h"
#include "ash/test/ash_test_base.h"
#include "ash/wm/pip/pip_positioner.h"
#include "ash/wm/window_state.h"
#include "ash/wm/wm_event.h"
#include "base/command_line.h"
#include "ui/aura/window.h"
#include "ui/events/test/event_generator.h"
#include "ui/keyboard/keyboard_controller.h"
#include "ui/keyboard/public/keyboard_switches.h"
#include "ui/keyboard/test/keyboard_test_util.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"
namespace ash {
using PipTest = AshTestBase;
namespace {
std::unique_ptr<views::Widget> CreateWidget() {
std::unique_ptr<views::Widget> CreateWidget(aura::Window* context) {
std::unique_ptr<views::Widget> widget(new views::Widget);
views::Widget::InitParams params;
params.delegate = new views::WidgetDelegateView();
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
params.context = Shell::GetPrimaryRootWindow();
params.context = context;
widget->Init(params);
return widget;
}
} // namespace
class PipTest : public AshTestBase {
public:
PipTest() = default;
~PipTest() override = default;
void SetUp() override {
base::CommandLine::ForCurrentProcess()->AppendSwitch(
keyboard::switches::kEnableVirtualKeyboard);
AshTestBase::SetUp();
}
void TearDown() override { AshTestBase::TearDown(); }
private:
DISALLOW_COPY_AND_ASSIGN(PipTest);
};
TEST_F(PipTest, ShowInactive) {
auto widget = CreateWidget();
auto widget = CreateWidget(Shell::GetPrimaryRootWindow());
const wm::WMEvent pip_event(wm::WM_EVENT_PIP);
auto* window_state = wm::GetWindowState(widget->GetNativeWindow());
window_state->OnWMEvent(&pip_event);
......@@ -62,8 +85,8 @@ TEST_F(PipTest, ShowInactive) {
}
TEST_F(PipTest, ShortcutNavigation) {
auto widget = CreateWidget();
auto pip_widget = CreateWidget();
auto widget = CreateWidget(Shell::GetPrimaryRootWindow());
auto pip_widget = CreateWidget(Shell::GetPrimaryRootWindow());
widget->Show();
pip_widget->Show();
const wm::WMEvent pip_event(wm::WM_EVENT_PIP);
......@@ -109,4 +132,125 @@ TEST_F(PipTest, ShortcutNavigation) {
EXPECT_TRUE(pip_widget->IsActive());
}
TEST_F(PipTest, PipInitialPositionAvoidsObstacles) {
UpdateDisplay("400x400");
std::unique_ptr<aura::Window> window(
CreateTestWindowInShellWithBounds(gfx::Rect(100, 300, 100, 100)));
wm::WindowState* window_state = wm::GetWindowState(window.get());
const wm::WMEvent enter_pip(wm::WM_EVENT_PIP);
window_state->OnWMEvent(&enter_pip);
window->Show();
Shell::Get()->EnableKeyboard();
auto* keyboard_controller = keyboard::KeyboardController::Get();
keyboard_controller->ShowKeyboard(/*lock=*/true);
ASSERT_TRUE(keyboard::WaitUntilShown());
aura::Window* keyboard_window = keyboard_controller->GetKeyboardWindow();
keyboard_window->SetBounds(gfx::Rect(0, 300, 400, 100));
// Expect the PIP position is shifted below the keyboard.
EXPECT_TRUE(window_state->IsPip());
EXPECT_TRUE(window->layer()->visible());
EXPECT_EQ(gfx::Rect(100, 192, 100, 100), window->layer()->GetTargetBounds());
}
TEST_F(PipTest, TargetBoundsAffectedByWorkAreaChange) {
UpdateDisplay("400x400");
Shell::Get()->EnableKeyboard();
// Place a keyboard window at the initial position of a PIP window.
auto* keyboard_controller = keyboard::KeyboardController::Get();
keyboard_controller->ShowKeyboard(/*lock=*/true);
ASSERT_TRUE(keyboard::WaitUntilShown());
aura::Window* keyboard_window = keyboard_controller->GetKeyboardWindow();
keyboard_window->SetBounds(gfx::Rect(0, 300, 400, 100));
std::unique_ptr<aura::Window> window(
CreateTestWindowInShellWithBounds(gfx::Rect(100, 300, 100, 100)));
wm::WindowState* window_state = wm::GetWindowState(window.get());
const wm::WMEvent enter_pip(wm::WM_EVENT_PIP);
window_state->OnWMEvent(&enter_pip);
window->Show();
// Ensure the initial PIP position is shifted below the keyboard.
EXPECT_TRUE(window_state->IsPip());
EXPECT_TRUE(window->layer()->visible());
EXPECT_EQ(gfx::Rect(100, 192, 100, 100), window->bounds());
}
TEST_F(PipTest, PipRestoresToPreviousBoundsOnMovementAreaChangeIfTheyExist) {
UpdateDisplay("400x400");
std::unique_ptr<aura::Window> window(
CreateTestWindowInShellWithBounds(gfx::Rect(200, 200, 100, 100)));
wm::WindowState* window_state = wm::GetWindowState(window.get());
const wm::WMEvent enter_pip(wm::WM_EVENT_PIP);
window_state->OnWMEvent(&enter_pip);
window->Show();
// Position the PIP window on the side of the screen where it will be next
// to an edge and therefore in a resting position for the whole test.
const gfx::Rect bounds = gfx::Rect(292, 200, 100, 100);
// Set restore position to where the window currently is.
window->SetBounds(bounds);
window_state->SetRestoreBoundsInParent(bounds);
EXPECT_TRUE(window_state->HasRestoreBounds());
// Update the work area so that the PIP window should be pushed upward.
UpdateDisplay("400x200");
Shell::Get()->SetDisplayWorkAreaInsets(Shell::GetPrimaryRootWindow(),
gfx::Insets());
// Set PIP to the updated constrained bounds.
const gfx::Rect constrained_bounds =
PipPositioner::GetPositionAfterMovementAreaChange(window_state);
EXPECT_EQ(gfx::Rect(292, 92, 100, 100), constrained_bounds);
window->SetBoundsInScreen(constrained_bounds, window_state->GetDisplay());
// Restore the original work area.
UpdateDisplay("400x400");
// Expect that the PIP window is put back to where it was before.
EXPECT_EQ(gfx::Rect(292, 200, 100, 100),
PipPositioner::GetPositionAfterMovementAreaChange(window_state));
}
TEST_F(
PipTest,
PipRestoresToPreviousBoundsOnMovementAreaChangeIfTheyExistOnExternalDisplay) {
UpdateDisplay("400x400,400x400");
auto* root_window = Shell::GetAllRootWindows()[1];
// Position the PIP window on the side of the screen where it will be next
// to an edge and therefore in a resting position for the whole test.
auto widget = CreateWidget(root_window);
auto* window = widget->GetNativeWindow();
wm::WindowState* window_state = wm::GetWindowState(window);
const wm::WMEvent enter_pip(wm::WM_EVENT_PIP);
window_state->OnWMEvent(&enter_pip);
window->Show();
window->SetBounds(gfx::Rect(8, 292, 100, 100));
// Set restore position to where the window currently is.
window_state->SetRestoreBoundsInParent(window->bounds());
EXPECT_TRUE(window_state->HasRestoreBounds());
// Update the work area so that the PIP window should be pushed upward.
UpdateDisplay("400x400,400x200");
Shell::Get()->SetDisplayWorkAreaInsets(root_window, gfx::Insets());
// Set PIP to the updated constrained bounds.
// const gfx::Rect constrained_bounds =
// PipPositioner::GetPositionAfterMovementAreaChange(window_state);
EXPECT_EQ(gfx::Rect(408, 92, 100, 100), window->GetBoundsInScreen());
// window->SetBoundsInScreen(constrained_bounds, window_state->GetDisplay());
// Restore the original work area.
UpdateDisplay("400x400,400x400");
Shell::Get()->SetDisplayWorkAreaInsets(root_window, gfx::Insets());
// Expect that the PIP window is put back to where it was before.
EXPECT_EQ(gfx::Rect(408, 292, 100, 100), window->GetBoundsInScreen());
// PipPositioner::GetPositionAfterMovementAreaChange(window_state));
}
} // namespace ash
......@@ -115,6 +115,9 @@ void PipWindowResizer::Drag(const gfx::Point& location_in_parent,
}
gfx::Rect new_bounds = CalculateBoundsForDrag(location_in_parent);
// We do everything in Screen coordinates, so convert here.
::wm::ConvertRectToScreen(GetTarget()->parent(), &new_bounds);
display::Display display = window_state()->GetDisplay();
gfx::Rect area = PipPositioner::GetMovementArea(display);
......@@ -133,14 +136,16 @@ void PipWindowResizer::Drag(const gfx::Point& location_in_parent,
// window is no longer poking outside of the movement area, disable any
// further swipe-to-dismiss gesture for this drag. Use the initial bounds
// to decide the locked axis position.
gfx::Rect initial_bounds_in_screen = details().initial_bounds_in_parent;
::wm::ConvertRectToScreen(GetTarget()->parent(), &initial_bounds_in_screen);
if (may_dismiss_horizontally_) {
if (IsPastLeftOrRightEdge(new_bounds, area))
new_bounds.set_y(details().initial_bounds_in_parent.y());
new_bounds.set_y(initial_bounds_in_screen.y());
else if (!IsAtLeftOrRightEdge(new_bounds, area))
may_dismiss_horizontally_ = false;
} else if (may_dismiss_vertically_) {
if (IsPastTopOrBottomEdge(new_bounds, area))
new_bounds.set_x(details().initial_bounds_in_parent.x());
new_bounds.set_x(initial_bounds_in_screen.x());
else if (!IsAtTopOrBottomEdge(new_bounds, area))
may_dismiss_vertically_ = false;
}
......@@ -149,9 +154,7 @@ void PipWindowResizer::Drag(const gfx::Point& location_in_parent,
if (!may_dismiss_horizontally_ && !may_dismiss_vertically_) {
// Reset opacity if it's not a dismiss gesture.
GetTarget()->layer()->SetOpacity(1.f);
::wm::ConvertRectToScreen(GetTarget()->parent(), &new_bounds);
new_bounds = PipPositioner::GetBoundsForDrag(display, new_bounds);
::wm::ConvertRectFromScreen(GetTarget()->parent(), &new_bounds);
} else {
gfx::Rect dismiss_bounds = new_bounds;
dismiss_bounds.Intersect(area);
......@@ -172,6 +175,8 @@ void PipWindowResizer::Drag(const gfx::Point& location_in_parent,
may_dismiss_vertically_ = false;
}
// Convert back to root window coordinates for setting bounds.
::wm::ConvertRectFromScreen(GetTarget()->parent(), &new_bounds);
if (new_bounds != GetTarget()->bounds()) {
moved_or_resized_ = true;
GetTarget()->SetBounds(new_bounds);
......
......@@ -8,6 +8,7 @@
#include <utility>
#include "ash/metrics/pip_uma.h"
#include "ash/scoped_root_window_for_new_windows.h"
#include "ash/shelf/shelf.h"
#include "ash/shell.h"
#include "ash/test/ash_test_base.h"
......@@ -71,7 +72,9 @@ class FakeWindowState : public wm::WindowState::State {
using Sample = base::HistogramBase::Sample;
class PipWindowResizerTest : public AshTestBase {
class PipWindowResizerTest : public AshTestBase,
public ::testing::WithParamInterface<
std::tuple<std::string, std::size_t>> {
public:
PipWindowResizerTest() = default;
~PipWindowResizerTest() override = default;
......@@ -81,18 +84,17 @@ class PipWindowResizerTest : public AshTestBase {
keyboard::switches::kEnableVirtualKeyboard);
AshTestBase::SetUp();
SetTouchKeyboardEnabled(true);
}
void PreparePipWindow(const gfx::Rect& bounds) {
widget_ = CreateWidgetForTest(bounds);
window_ = widget_->GetNativeWindow();
window_->SetProperty(aura::client::kAlwaysOnTopKey, true);
test_state_ = new FakeWindowState(mojom::WindowStateType::PIP);
wm::GetWindowState(window_)->SetStateObject(
std::unique_ptr<wm::WindowState::State>(test_state_));
const std::string& display_string = std::get<0>(GetParam());
const std::size_t root_window_index = std::get<1>(GetParam());
UpdateWorkArea(display_string);
ASSERT_LT(root_window_index, Shell::GetAllRootWindows().size());
scoped_root_.reset(new ScopedRootWindowForNewWindows(
Shell::GetAllRootWindows()[root_window_index]));
}
void TearDown() override {
scoped_root_.reset();
SetTouchKeyboardEnabled(false);
AshTestBase::TearDown();
}
......@@ -104,18 +106,36 @@ class PipWindowResizerTest : public AshTestBase {
base::HistogramTester& histograms() { return histograms_; }
std::unique_ptr<views::Widget> CreateWidgetForTest(const gfx::Rect& bounds) {
return CreateTestWidget(nullptr, kShellWindowId_AlwaysOnTopContainer,
bounds);
auto* root_window = Shell::GetRootWindowForNewWindows();
gfx::Rect screen_bounds = bounds;
::wm::ConvertRectToScreen(root_window, &screen_bounds);
std::unique_ptr<views::Widget> widget(new views::Widget);
views::Widget::InitParams params;
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
params.bounds = screen_bounds;
params.keep_on_top = true;
params.context = root_window;
widget->Init(params);
widget->Show();
return widget;
}
PipWindowResizer* CreateResizerForTest(int window_component) {
return CreateResizerForTest(window_component, window());
return CreateResizerForTest(window_component, window(),
window()->bounds().CenterPoint());
}
PipWindowResizer* CreateResizerForTest(int window_component,
aura::Window* window) {
gfx::Point point_in_parent) {
return CreateResizerForTest(window_component, window(), point_in_parent);
}
PipWindowResizer* CreateResizerForTest(int window_component,
aura::Window* window,
gfx::Point point_in_parent) {
wm::WindowState* window_state = wm::GetWindowState(window);
window_state->CreateDragDetails(gfx::Point(), window_component,
window_state->CreateDragDetails(point_in_parent, window_component,
::wm::WINDOW_MOVE_SOURCE_MOUSE);
return new PipWindowResizer(window_state);
}
......@@ -143,10 +163,12 @@ class PipWindowResizerTest : public AshTestBase {
resizer->FlingOrSwipe(&event);
}
void UpdateWorkArea(const std::string& bounds) {
UpdateDisplay(bounds);
aura::Window* root = Shell::GetPrimaryRootWindow();
Shell::Get()->SetDisplayWorkAreaInsets(root, gfx::Insets());
void PreparePipWindow(const gfx::Rect& bounds) {
widget_ = CreateWidgetForTest(bounds);
window_ = widget_->GetNativeWindow();
test_state_ = new FakeWindowState(mojom::WindowStateType::PIP);
wm::GetWindowState(window_)->SetStateObject(
std::unique_ptr<wm::WindowState::State>(test_state_));
}
private:
......@@ -154,13 +176,20 @@ class PipWindowResizerTest : public AshTestBase {
aura::Window* window_;
FakeWindowState* test_state_;
base::HistogramTester histograms_;
std::unique_ptr<ScopedRootWindowForNewWindows> scoped_root_;
void UpdateWorkArea(const std::string& bounds) {
UpdateDisplay(bounds);
for (aura::Window* root : Shell::GetAllRootWindows())
Shell::Get()->SetDisplayWorkAreaInsets(root, gfx::Insets());
}
DISALLOW_COPY_AND_ASSIGN(PipWindowResizerTest);
};
TEST_F(PipWindowResizerTest, PipWindowCanDrag) {
UpdateWorkArea("400x800");
TEST_P(PipWindowResizerTest, PipWindowCanDrag) {
PreparePipWindow(gfx::Rect(200, 200, 100, 100));
std::unique_ptr<PipWindowResizer> resizer(CreateResizerForTest(HTCAPTION));
ASSERT_TRUE(resizer.get());
......@@ -168,8 +197,7 @@ TEST_F(PipWindowResizerTest, PipWindowCanDrag) {
EXPECT_EQ(gfx::Rect(200, 210, 100, 100), test_state()->last_bounds());
}
TEST_F(PipWindowResizerTest, PipWindowCanResize) {
UpdateWorkArea("400x800");
TEST_P(PipWindowResizerTest, PipWindowCanResize) {
PreparePipWindow(gfx::Rect(200, 200, 100, 100));
std::unique_ptr<PipWindowResizer> resizer(CreateResizerForTest(HTBOTTOM));
ASSERT_TRUE(resizer.get());
......@@ -178,33 +206,35 @@ TEST_F(PipWindowResizerTest, PipWindowCanResize) {
EXPECT_EQ(gfx::Rect(200, 200, 100, 110), test_state()->last_bounds());
}
TEST_F(PipWindowResizerTest, PipWindowDragIsRestrictedToWorkArea) {
UpdateWorkArea("400x400");
TEST_P(PipWindowResizerTest, PipWindowDragIsRestrictedToWorkArea) {
PreparePipWindow(gfx::Rect(200, 200, 100, 100));
std::unique_ptr<PipWindowResizer> resizer(CreateResizerForTest(HTCAPTION));
// Specify point in parent as center so the drag point does not leave the
// display. If the drag point is not in any display bounds, it causes the
// window to be moved to the default display.
std::unique_ptr<PipWindowResizer> resizer(
CreateResizerForTest(HTCAPTION, gfx::Point(250, 250)));
ASSERT_TRUE(resizer.get());
// Drag to the right.
resizer->Drag(CalculateDragPoint(*resizer, 800, 0), 0);
resizer->Drag(CalculateDragPoint(*resizer, 250, 0), 0);
EXPECT_EQ(gfx::Rect(292, 200, 100, 100), test_state()->last_bounds());
// Drag down.
resizer->Drag(CalculateDragPoint(*resizer, 0, 800), 0);
resizer->Drag(CalculateDragPoint(*resizer, 0, 250), 0);
EXPECT_EQ(gfx::Rect(200, 292, 100, 100), test_state()->last_bounds());
// Drag to the left.
resizer->Drag(CalculateDragPoint(*resizer, -800, 0), 0);
resizer->Drag(CalculateDragPoint(*resizer, -250, 0), 0);
EXPECT_EQ(gfx::Rect(8, 200, 100, 100), test_state()->last_bounds());
// Drag up.
resizer->Drag(CalculateDragPoint(*resizer, 0, -800), 0);
resizer->Drag(CalculateDragPoint(*resizer, 0, -250), 0);
EXPECT_EQ(gfx::Rect(200, 8, 100, 100), test_state()->last_bounds());
}
TEST_F(PipWindowResizerTest, PipWindowCanBeDraggedInTabletMode) {
TEST_P(PipWindowResizerTest, PipWindowCanBeDraggedInTabletMode) {
Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
UpdateWorkArea("400x800");
PreparePipWindow(gfx::Rect(200, 200, 100, 100));
std::unique_ptr<PipWindowResizer> resizer(CreateResizerForTest(HTCAPTION));
ASSERT_TRUE(resizer.get());
......@@ -213,10 +243,9 @@ TEST_F(PipWindowResizerTest, PipWindowCanBeDraggedInTabletMode) {
EXPECT_EQ(gfx::Rect(200, 210, 100, 100), test_state()->last_bounds());
}
TEST_F(PipWindowResizerTest, PipWindowCanBeResizedInTabletMode) {
TEST_P(PipWindowResizerTest, PipWindowCanBeResizedInTabletMode) {
Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
UpdateWorkArea("400x800");
PreparePipWindow(gfx::Rect(200, 200, 100, 100));
std::unique_ptr<PipWindowResizer> resizer(CreateResizerForTest(HTBOTTOM));
ASSERT_TRUE(resizer.get());
......@@ -225,8 +254,7 @@ TEST_F(PipWindowResizerTest, PipWindowCanBeResizedInTabletMode) {
EXPECT_EQ(gfx::Rect(200, 200, 100, 110), test_state()->last_bounds());
}
TEST_F(PipWindowResizerTest, PipWindowCanBeSwipeDismissed) {
UpdateWorkArea("400x400");
TEST_P(PipWindowResizerTest, PipWindowCanBeSwipeDismissed) {
PreparePipWindow(gfx::Rect(8, 8, 100, 100));
std::unique_ptr<PipWindowResizer> resizer(CreateResizerForTest(HTCAPTION));
ASSERT_TRUE(resizer.get());
......@@ -239,8 +267,7 @@ TEST_F(PipWindowResizerTest, PipWindowCanBeSwipeDismissed) {
EXPECT_TRUE(widget()->IsClosed());
}
TEST_F(PipWindowResizerTest, PipWindowPartiallySwipedDoesNotDismiss) {
UpdateWorkArea("400x400");
TEST_P(PipWindowResizerTest, PipWindowPartiallySwipedDoesNotDismiss) {
PreparePipWindow(gfx::Rect(8, 8, 100, 100));
std::unique_ptr<PipWindowResizer> resizer(CreateResizerForTest(HTCAPTION));
ASSERT_TRUE(resizer.get());
......@@ -254,10 +281,10 @@ TEST_F(PipWindowResizerTest, PipWindowPartiallySwipedDoesNotDismiss) {
EXPECT_EQ(gfx::Rect(8, 8, 100, 100), test_state()->last_bounds());
}
TEST_F(PipWindowResizerTest, PipWindowInSwipeToDismissGestureLocksToAxis) {
UpdateWorkArea("400x400");
TEST_P(PipWindowResizerTest, PipWindowInSwipeToDismissGestureLocksToAxis) {
PreparePipWindow(gfx::Rect(8, 8, 100, 100));
std::unique_ptr<PipWindowResizer> resizer(CreateResizerForTest(HTCAPTION));
std::unique_ptr<PipWindowResizer> resizer(
CreateResizerForTest(HTCAPTION, gfx::Point(50, 50)));
ASSERT_TRUE(resizer.get());
// Drag to the left, but only a little bit, to start a swipe-to-dismiss.
......@@ -269,9 +296,8 @@ TEST_F(PipWindowResizerTest, PipWindowInSwipeToDismissGestureLocksToAxis) {
EXPECT_EQ(gfx::Rect(-22, 8, 100, 100), test_state()->last_bounds());
}
TEST_F(PipWindowResizerTest,
TEST_P(PipWindowResizerTest,
PipWindowMovedAwayFromScreenEdgeNoLongerCanSwipeToDismiss) {
UpdateWorkArea("400x400");
PreparePipWindow(gfx::Rect(8, 16, 100, 100));
std::unique_ptr<PipWindowResizer> resizer(CreateResizerForTest(HTCAPTION));
ASSERT_TRUE(resizer.get());
......@@ -286,8 +312,7 @@ TEST_F(PipWindowResizerTest,
EXPECT_EQ(gfx::Rect(8, 8, 100, 100), test_state()->last_bounds());
}
TEST_F(PipWindowResizerTest, PipWindowAtCornerLocksToOneAxisOnSwipeToDismiss) {
UpdateWorkArea("400x400");
TEST_P(PipWindowResizerTest, PipWindowAtCornerLocksToOneAxisOnSwipeToDismiss) {
PreparePipWindow(gfx::Rect(8, 8, 100, 100));
std::unique_ptr<PipWindowResizer> resizer(CreateResizerForTest(HTCAPTION));
ASSERT_TRUE(resizer.get());
......@@ -298,10 +323,9 @@ TEST_F(PipWindowResizerTest, PipWindowAtCornerLocksToOneAxisOnSwipeToDismiss) {
EXPECT_EQ(gfx::Rect(8, -32, 100, 100), test_state()->last_bounds());
}
TEST_F(
TEST_P(
PipWindowResizerTest,
PipWindowMustBeDraggedMostlyInDirectionOfDismissToInitiateSwipeToDismiss) {
UpdateWorkArea("400x400");
PreparePipWindow(gfx::Rect(8, 8, 100, 100));
std::unique_ptr<PipWindowResizer> resizer(CreateResizerForTest(HTCAPTION));
ASSERT_TRUE(resizer.get());
......@@ -311,9 +335,8 @@ TEST_F(
EXPECT_EQ(gfx::Rect(8, 58, 100, 100), test_state()->last_bounds());
}
TEST_F(PipWindowResizerTest,
TEST_P(PipWindowResizerTest,
PipWindowDoesNotMoveUntilStatusOfSwipeToDismissGestureIsKnown) {
UpdateWorkArea("400x400");
PreparePipWindow(gfx::Rect(8, 8, 100, 100));
std::unique_ptr<PipWindowResizer> resizer(CreateResizerForTest(HTCAPTION));
ASSERT_TRUE(resizer.get());
......@@ -324,8 +347,7 @@ TEST_F(PipWindowResizerTest,
EXPECT_TRUE(test_state()->last_bounds().IsEmpty());
}
TEST_F(PipWindowResizerTest, PipWindowIsFlungToEdge) {
UpdateWorkArea("400x400");
TEST_P(PipWindowResizerTest, PipWindowIsFlungToEdge) {
PreparePipWindow(gfx::Rect(200, 200, 100, 100));
{
......@@ -373,8 +395,7 @@ TEST_F(PipWindowResizerTest, PipWindowIsFlungToEdge) {
}
}
TEST_F(PipWindowResizerTest, PipWindowIsFlungDiagonally) {
UpdateWorkArea("400x400");
TEST_P(PipWindowResizerTest, PipWindowIsFlungDiagonally) {
PreparePipWindow(gfx::Rect(200, 200, 100, 100));
{
......@@ -477,14 +498,15 @@ TEST_F(PipWindowResizerTest, PipWindowIsFlungDiagonally) {
}
}
TEST_F(PipWindowResizerTest, PipWindowFlungAvoidsFloatingKeyboard) {
PreparePipWindow(gfx::Rect(200, 200, 100, 100));
TEST_P(PipWindowResizerTest, PipWindowFlungAvoidsFloatingKeyboard) {
PreparePipWindow(gfx::Rect(200, 200, 75, 75));
auto* keyboard_controller = keyboard::KeyboardController::Get();
keyboard_controller->SetContainerType(
keyboard::mojom::ContainerType::kFloating, gfx::Rect(0, 0, 1, 1),
base::DoNothing());
keyboard_controller->ShowKeyboard(/*lock=*/true);
keyboard_controller->ShowKeyboardInDisplay(
wm::GetWindowState(window())->GetDisplay());
ASSERT_TRUE(keyboard::WaitUntilShown());
aura::Window* keyboard_window = keyboard_controller->GetKeyboardWindow();
......@@ -498,61 +520,30 @@ TEST_F(PipWindowResizerTest, PipWindowFlungAvoidsFloatingKeyboard) {
Fling(std::move(resizer), -4000.f, 0.f);
// Appear below the keyboard.
EXPECT_EQ(gfx::Rect(8, 258, 100, 100), test_state()->last_bounds());
EXPECT_EQ(gfx::Rect(8, 258, 75, 75), test_state()->last_bounds());
}
TEST_F(PipWindowResizerTest, PipWindowInsidePrimaryDisplay) {
UpdateWorkArea("400x400,400x400");
// Ensure the initial position is in the primary display.
const display::Display& primary_display =
Shell::Get()->display_manager()->GetDisplayAt(0);
TEST_P(PipWindowResizerTest, PipWindowDoesNotChangeDisplayOnDrag) {
PreparePipWindow(gfx::Rect(200, 200, 100, 100));
display::Display display = wm::GetWindowState(window())->GetDisplay();
gfx::Rect rect_in_screen = window()->bounds();
::wm::ConvertRectToScreen(window()->parent(), &rect_in_screen);
EXPECT_TRUE(primary_display.bounds().Contains(rect_in_screen));
EXPECT_TRUE(display.bounds().Contains(rect_in_screen));
// Drag inside the display.
std::unique_ptr<PipWindowResizer> resizer(CreateResizerForTest(HTCAPTION));
ASSERT_TRUE(resizer.get());
resizer->Drag(CalculateDragPoint(*resizer, 10, 10), 0);
// Ensure the position is still in the primary display.
// Ensure the position is still in the display.
EXPECT_EQ(gfx::Rect(210, 210, 100, 100), test_state()->last_bounds());
EXPECT_EQ(primary_display.id(),
test_state()->last_window_state()->GetDisplay().id());
EXPECT_EQ(display.id(), test_state()->last_window_state()->GetDisplay().id());
rect_in_screen = window()->bounds();
::wm::ConvertRectToScreen(window()->parent(), &rect_in_screen);
EXPECT_TRUE(primary_display.bounds().Contains(rect_in_screen));
EXPECT_TRUE(display.bounds().Contains(rect_in_screen));
}
TEST_F(PipWindowResizerTest, PipWindowInsideExternalDisplay) {
UpdateWorkArea("400x400,400x400");
// Ensure the initial position is in the secondary display.
const display::Display& secondary_display =
Shell::Get()->display_manager()->GetDisplayAt(1);
PreparePipWindow(gfx::Rect(600, 200, 100, 100));
gfx::Rect rect_in_screen = window()->bounds();
::wm::ConvertRectToScreen(window()->parent(), &rect_in_screen);
EXPECT_TRUE(secondary_display.bounds().Contains(rect_in_screen));
// Drag inside the display.
std::unique_ptr<PipWindowResizer> resizer(CreateResizerForTest(HTCAPTION));
ASSERT_TRUE(resizer.get());
resizer->Drag(CalculateDragPoint(*resizer, 10, 10), 0);
// Ensure the position is still in the secondary display.
EXPECT_EQ(gfx::Rect(210, 210, 100, 100), test_state()->last_bounds());
EXPECT_EQ(secondary_display.id(),
test_state()->last_window_state()->GetDisplay().id());
rect_in_screen = window()->bounds();
::wm::ConvertRectToScreen(window()->parent(), &rect_in_screen);
EXPECT_TRUE(secondary_display.bounds().Contains(rect_in_screen));
}
TEST_F(PipWindowResizerTest, PipRestoreBoundsSetOnFling) {
UpdateWorkArea("400x400");
TEST_P(PipWindowResizerTest, PipRestoreBoundsSetOnFling) {
PreparePipWindow(gfx::Rect(200, 200, 100, 100));
{
......@@ -566,11 +557,10 @@ TEST_F(PipWindowResizerTest, PipRestoreBoundsSetOnFling) {
wm::WindowState* window_state = wm::GetWindowState(window());
EXPECT_TRUE(window_state->HasRestoreBounds());
EXPECT_EQ(gfx::Rect(292, 292, 100, 100),
window_state->GetRestoreBoundsInScreen());
window_state->GetRestoreBoundsInParent());
}
TEST_F(PipWindowResizerTest, PipStartAndFinishFreeResizeUmaMetrics) {
UpdateWorkArea("400x400");
TEST_P(PipWindowResizerTest, PipStartAndFinishFreeResizeUmaMetrics) {
PreparePipWindow(gfx::Rect(200, 200, 100, 100));
std::unique_ptr<PipWindowResizer> resizer(CreateResizerForTest(HTBOTTOM));
ASSERT_TRUE(resizer.get());
......@@ -585,8 +575,7 @@ TEST_F(PipWindowResizerTest, PipStartAndFinishFreeResizeUmaMetrics) {
histograms().ExpectTotalCount(kAshPipEventsHistogramName, 1);
}
TEST_F(PipWindowResizerTest, PipFreeResizeAreaUmaMetrics) {
UpdateWorkArea("400x400");
TEST_P(PipWindowResizerTest, PipFreeResizeAreaUmaMetrics) {
PreparePipWindow(gfx::Rect(200, 200, 100, 100));
std::unique_ptr<PipWindowResizer> resizer(CreateResizerForTest(HTBOTTOM));
ASSERT_TRUE(resizer.get());
......@@ -603,5 +592,18 @@ TEST_F(PipWindowResizerTest, PipFreeResizeAreaUmaMetrics) {
histograms().ExpectTotalCount(kAshPipFreeResizeFinishAreaHistogramName, 1);
}
// TODO: UpdateDisplay() doesn't support different layouts of multiple displays.
// We should add some way to try multiple layouts.
INSTANTIATE_TEST_SUITE_P(
/* no prefix */,
PipWindowResizerTest,
testing::Values(std::make_tuple("400x400", 0u),
std::make_tuple("400x400/r", 0u),
std::make_tuple("400x400/u", 0u),
std::make_tuple("400x400/l", 0u),
std::make_tuple("800x800*2", 0u),
std::make_tuple("400x400,400x400", 0u),
std::make_tuple("400x400,400x400", 1u)));
} // namespace wm
} // namespace ash
......@@ -741,7 +741,8 @@ void WindowState::UpdatePipState(mojom::WindowStateType old_window_state_type) {
void WindowState::UpdatePipBounds() {
gfx::Rect new_bounds =
PipPositioner::GetPositionAfterMovementAreaChange(this);
if (window()->GetBoundsInScreen() != new_bounds) {
::wm::ConvertRectFromScreen(window()->GetRootWindow(), &new_bounds);
if (window()->bounds() != new_bounds) {
wm::SetBoundsEvent event(wm::WM_EVENT_SET_BOUNDS, new_bounds,
/*animate=*/true);
OnWMEvent(&event);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment