#include "base/compiler_specific.h"
#include "base/memory/scoped_vector.h"
#include "base/run_loop.h"
+#include "base/strings/string_piece.h"
#include "base/strings/utf_string_conversions.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/client/cursor_client.h"
#include "ui/aura/client/focus_client.h"
-#include "ui/aura/test/event_generator.h"
#include "ui/aura/test/test_window_delegate.h"
#include "ui/aura/test/test_windows.h"
#include "ui/aura/window.h"
#include "ui/aura/window_event_dispatcher.h"
#include "ui/compositor/scoped_animation_duration_scale_mode.h"
+#include "ui/events/test/event_generator.h"
#include "ui/gfx/rect_conversions.h"
#include "ui/gfx/transform.h"
#include "ui/views/controls/label.h"
}
void ClickWindow(aura::Window* window) {
- aura::test::EventGenerator event_generator(window->GetRootWindow(), window);
+ ui::test::EventGenerator event_generator(window->GetRootWindow(), window);
gfx::RectF target = GetTransformedBounds(window);
event_generator.ClickLeftButton();
}
void SendKey(ui::KeyboardCode key) {
- aura::test::EventGenerator event_generator(Shell::GetPrimaryRootWindow());
+ ui::test::EventGenerator event_generator(Shell::GetPrimaryRootWindow());
event_generator.PressKey(key, 0);
event_generator.ReleaseKey(key, 0);
}
SelectedWindow()->SelectionWindow();
}
+ const bool selection_widget_active() {
+ WindowSelector* ws = ash::Shell::GetInstance()->
+ window_selector_controller()->window_selector_.get();
+ return ws->grid_list_[ws->selected_grid_index_]->is_selecting();
+ }
+
+ bool showing_filter_widget() {
+ WindowSelector* ws = ash::Shell::GetInstance()->
+ window_selector_controller()->window_selector_.get();
+ return ws->text_filter_widget_->GetNativeWindow()->layer()->
+ GetTargetTransform().IsIdentity();
+ }
+
views::Widget* GetCloseButton(ash::WindowSelectorItem* window) {
return window->close_button_.get();
}
- views::Widget* GetLabelWidget(ash::WindowSelectorItem* window) {
- return window->window_label_.get();
+ views::Label* GetLabelView(ash::WindowSelectorItem* window) {
+ return window->window_label_view_;
}
// Tests that a window is contained within a given WindowSelectorItem, and
GetCloseButton(window_item)->GetNativeView()))));
}
+ void FilterItems(const base::StringPiece& pattern) {
+ ash::Shell::GetInstance()->
+ window_selector_controller()->window_selector_.get()->
+ ContentsChanged(NULL, base::UTF8ToUTF16(pattern));
+ }
+
test::ShelfViewTestAPI* shelf_view_test() {
return shelf_view_test_.get();
}
+ views::Widget* text_filter_widget() {
+ return ash::Shell::GetInstance()->
+ window_selector_controller()->window_selector_.get()->
+ text_filter_widget_.get();
+ }
+
private:
aura::test::TestWindowDelegate delegate_;
NonActivatableActivationDelegate non_activatable_activation_delegate_;
// Hide the cursor before entering overview to test that it will be shown.
aura::client::GetCursorClient(root_window)->HideCursor();
- // In overview mode the windows should no longer overlap and focus should
- // be removed from the window.
+ // In overview mode the windows should no longer overlap and the text filter
+ // widget should be focused.
ToggleOverview();
- EXPECT_EQ(NULL, GetFocusedWindow());
+ EXPECT_EQ(text_filter_widget()->GetNativeWindow(), GetFocusedWindow());
EXPECT_FALSE(WindowsOverlapping(window1.get(), window2.get()));
EXPECT_FALSE(WindowsOverlapping(window1.get(), panel1.get()));
// Panels 1 and 2 should still be overlapping being in a single selector
wm::ActivateWindow(window1.get());
EXPECT_EQ(window1.get(), GetFocusedWindow());
ToggleOverview();
- EXPECT_EQ(NULL, GetFocusedWindow());
- aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
- window2.get());
+ EXPECT_EQ(text_filter_widget()->GetNativeWindow(), GetFocusedWindow());
+ ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
+ window2.get());
generator.GestureTapAt(gfx::ToEnclosingRect(
GetTransformedTargetBounds(window2.get())).CenterPoint());
EXPECT_EQ(window2.get(), GetFocusedWindow());
aura::Window* window2 = widget->GetNativeWindow();
gfx::RectF bounds = GetTransformedBoundsInRootWindow(window2);
gfx::Point point(bounds.top_right().x() - 1, bounds.top_right().y() - 1);
- aura::test::EventGenerator event_generator(window2->GetRootWindow(), point);
+ ui::test::EventGenerator event_generator(window2->GetRootWindow(), point);
EXPECT_FALSE(widget->IsClosed());
event_generator.ClickLeftButton();
gfx::Rect bounds(0, 0, 400, 400);
scoped_ptr<aura::Window> window1(CreateWindow(bounds));
scoped_ptr<aura::Window> window2(CreateWindow(bounds));
- Shell::GetInstance()->ToggleAppList(NULL);
+ Shell::GetInstance()->ShowAppList(NULL);
EXPECT_TRUE(Shell::GetInstance()->GetAppListTargetVisibility());
ToggleOverview();
EXPECT_FALSE(Shell::GetInstance()->GetAppListTargetVisibility());
EXPECT_FALSE(window1->IsVisible());
EXPECT_FALSE(window1->layer()->GetTargetVisibility());
{
- ui::ScopedAnimationDurationScaleMode normal_duration_mode(
- ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION);
+ ui::ScopedAnimationDurationScaleMode test_duration_mode(
+ ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
ToggleOverview();
EXPECT_TRUE(window1->IsVisible());
EXPECT_TRUE(window1->layer()->GetTargetVisibility());
}
{
- ui::ScopedAnimationDurationScaleMode normal_duration_mode(
- ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION);
+ ui::ScopedAnimationDurationScaleMode test_duration_mode(
+ ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
ToggleOverview();
EXPECT_FALSE(window1->IsVisible());
EXPECT_FALSE(window1->layer()->GetTargetVisibility());
wm::ActivateWindow(window.get());
EXPECT_EQ(window.get(), GetFocusedWindow());
- // In overview mode, focus should be removed.
+ // In overview mode, the text filter widget should be focused.
ToggleOverview();
- EXPECT_EQ(NULL, GetFocusedWindow());
+ EXPECT_EQ(text_filter_widget()->GetNativeWindow(), GetFocusedWindow());
// If canceling overview mode, focus should be restored.
ToggleOverview();
// animating when we reenter. We cannot short circuit animations for this but
// we also don't have to wait for them to complete.
{
- ui::ScopedAnimationDurationScaleMode normal_duration_mode(
- ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION);
+ ui::ScopedAnimationDurationScaleMode test_duration_mode(
+ ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
ToggleOverview();
ToggleOverview();
}
TEST_F(WindowSelectorTest, CreateLabelUnderWindow) {
scoped_ptr<aura::Window> window(CreateWindow(gfx::Rect(0, 0, 100, 100)));
base::string16 window_title = base::UTF8ToUTF16("My window");
- window->set_title(window_title);
+ window->SetTitle(window_title);
ToggleOverview();
WindowSelectorItem* window_item = GetWindowItemsForRoot(0).back();
- views::Widget* widget = GetLabelWidget(window_item);
- // Has the label widget been created?
- ASSERT_TRUE(widget);
- views::Label* label = static_cast<views::Label*>(widget->GetContentsView());
+ views::Label* label = GetLabelView(window_item);
+ // Has the label view been created?
+ ASSERT_TRUE(label);
+
// Verify the label matches the window title.
EXPECT_EQ(label->text(), window_title);
+
+ // Update the window title and check that the label is updated, too.
+ base::string16 updated_title = base::UTF8ToUTF16("Updated title");
+ window->SetTitle(updated_title);
+ EXPECT_EQ(label->text(), updated_title);
+
// Labels are located based on target_bounds, not the actual window item
// bounds.
gfx::Rect target_bounds(window_item->target_bounds());
gfx::Rect expected_label_bounds(target_bounds.x(),
- target_bounds.bottom(),
+ target_bounds.bottom() - label->
+ GetPreferredSize().height(),
target_bounds.width(),
label->GetPreferredSize().height());
- gfx::Rect real_label_bounds = widget->GetNativeWindow()->bounds();
- EXPECT_EQ(widget->GetNativeWindow()->bounds(), real_label_bounds);
+ gfx::Rect real_label_bounds = label->GetWidget()->GetNativeWindow()->bounds();
+ EXPECT_EQ(real_label_bounds, expected_label_bounds);
}
// Tests that a label is created for the active panel in a group of panels in
scoped_ptr<aura::Window> panel2(CreatePanelWindow(gfx::Rect(0, 0, 100, 100)));
base::string16 panel1_title = base::UTF8ToUTF16("My panel");
base::string16 panel2_title = base::UTF8ToUTF16("Another panel");
- panel1->set_title(panel1_title);
- panel2->set_title(panel2_title);
+ base::string16 updated_panel1_title = base::UTF8ToUTF16("WebDriver Torso");
+ base::string16 updated_panel2_title = base::UTF8ToUTF16("Da panel");
+ panel1->SetTitle(panel1_title);
+ panel2->SetTitle(panel2_title);
wm::ActivateWindow(panel1.get());
ToggleOverview();
WindowSelectorItem* window_item = GetWindowItemsForRoot(0).back();
- views::Widget* widget = GetLabelWidget(window_item);
- // Has the label widget been created?
- ASSERT_TRUE(widget);
- views::Label* label = static_cast<views::Label*>(widget->GetContentsView());
+ views::Label* label = GetLabelView(window_item);
+ // Has the label view been created?
+ ASSERT_TRUE(label);
+
// Verify the label matches the active window title.
EXPECT_EQ(label->text(), panel1_title);
+ // Verify that updating the title also updates the label.
+ panel1->SetTitle(updated_panel1_title);
+ EXPECT_EQ(label->text(), updated_panel1_title);
+ // After destroying the first panel, the label should match the second panel.
+ panel1.reset();
+ label = GetLabelView(window_item);
+ EXPECT_EQ(label->text(), panel2_title);
+ // Also test updating the title on the second panel.
+ panel2->SetTitle(updated_panel2_title);
+ EXPECT_EQ(label->text(), updated_panel2_title);
}
// Tests that overview updates the window positions if the display orientation
}
}
+// Tests traversing some windows in overview mode with the tab key.
+TEST_F(WindowSelectorTest, BasicTabKeyNavigation) {
+ gfx::Rect bounds(0, 0, 100, 100);
+ scoped_ptr<aura::Window> window2(CreateWindow(bounds));
+ scoped_ptr<aura::Window> window1(CreateWindow(bounds));
+ ToggleOverview();
+
+ SendKey(ui::VKEY_TAB);
+ EXPECT_EQ(GetSelectedWindow(), window1.get());
+ SendKey(ui::VKEY_TAB);
+ EXPECT_EQ(GetSelectedWindow(), window2.get());
+ SendKey(ui::VKEY_TAB);
+ EXPECT_EQ(GetSelectedWindow(), window1.get());
+}
+
// Tests traversing some windows in overview mode with the arrow keys in every
// possible direction.
TEST_F(WindowSelectorTest, BasicArrowKeyNavigation) {
if (!SupportsHostWindowResize())
return;
- const size_t test_windows = 7;
- UpdateDisplay("400x300");
+ const size_t test_windows = 9;
+ UpdateDisplay("800x600");
ScopedVector<aura::Window> windows;
for (size_t i = test_windows; i > 0; i--)
windows.push_back(CreateWindowWithId(gfx::Rect(0, 0, 100, 100), i));
ui::VKEY_LEFT,
ui::VKEY_UP
};
- // Expected window layout:
- // +-------+ +-------+ +-------+
- // | 1 | | 2 | | 3 |
- // +-------+ +-------+ +-------+
- // +-------+ +-------+ +-------+
- // | 4 | | 5 | | 6 |
- // +-------+ +-------+ +-------+
+ // Expected window layout, assuming that the text filtering feature is
+ // enabled by default (i.e., --ash-disable-text-filtering-in-overview-mode
+ // is not being used).
+ // +-------+ +-------+ +-------+ +-------+
+ // | 1 | | 2 | | 3 | | 4 |
+ // +-------+ +-------+ +-------+ +-------+
+ // +-------+ +-------+ +-------+ +-------+
+ // | 5 | | 6 | | 7 | | 8 |
+ // +-------+ +-------+ +-------+ +-------+
// +-------+
- // | 7 |
+ // | 9 |
// +-------+
// Index for each window during a full loop plus wrapping around.
int index_path_for_direction[][test_windows + 1] = {
- {1, 2, 3, 4, 5, 6, 7, 1}, // Right
- {1, 4, 7, 2, 5, 3, 6, 1}, // Down
- {7, 6, 5, 4, 3, 2, 1, 7}, // Left
- {6, 3, 5, 2, 7, 4, 1, 6} // Up
+ {1, 2, 3, 4, 5, 6, 7, 8, 9, 1}, // Right
+ {1, 5, 9, 2, 6, 3, 7, 4, 8, 1}, // Down
+ {9, 8, 7, 6, 5, 4, 3, 2, 1, 9}, // Left
+ {8, 4, 7, 3, 6, 2, 9, 5, 1, 8} // Up
};
for (size_t key_index = 0; key_index < arraysize(arrow_keys); key_index++) {
ToggleOverview();
for (size_t i = 0; i < test_windows + 1; i++) {
SendKey(arrow_keys[key_index]);
- // TODO(nsatragno): Add a more readable error message by constructing a
+ // TODO(flackr): Add a more readable error message by constructing a
// string from the window IDs.
EXPECT_EQ(GetSelectedWindow()->id(),
index_path_for_direction[key_index][i]);
aura::Window* window2 = widget2->GetNativeWindow();
base::string16 panel1_title = base::UTF8ToUTF16("Panel 1");
base::string16 panel2_title = base::UTF8ToUTF16("Panel 2");
- window1->set_title(panel1_title);
- window2->set_title(panel2_title);
+ window1->SetTitle(panel1_title);
+ window2->SetTitle(panel2_title);
wm::ActivateWindow(window1);
ToggleOverview();
gfx::RectF bounds1 = GetTransformedBoundsInRootWindow(window1);
gfx::Point point1(bounds1.top_right().x() - 1, bounds1.top_right().y() - 1);
- aura::test::EventGenerator event_generator1(window1->GetRootWindow(), point1);
+ ui::test::EventGenerator event_generator1(window1->GetRootWindow(), point1);
EXPECT_FALSE(widget1->IsClosed());
event_generator1.ClickLeftButton();
EXPECT_TRUE(window_item->Contains(window2));
EXPECT_TRUE(GetCloseButton(window_item)->IsVisible());
- views::Widget* widget = GetLabelWidget(window_item);
- views::Label* label = static_cast<views::Label*>(widget->GetContentsView());
+
+ views::Label* label = GetLabelView(window_item);
EXPECT_EQ(label->text(), panel2_title);
gfx::RectF bounds2 = GetTransformedBoundsInRootWindow(window2);
gfx::Point point2(bounds2.top_right().x() - 1, bounds2.top_right().y() - 1);
- aura::test::EventGenerator event_generator2(window2->GetRootWindow(), point2);
+ ui::test::EventGenerator event_generator2(window2->GetRootWindow(), point2);
EXPECT_FALSE(widget2->IsClosed());
event_generator2.ClickLeftButton();
EXPECT_FALSE(IsSelecting());
}
+// Creates three windows and tests filtering them by title.
+TEST_F(WindowSelectorTest, BasicTextFiltering) {
+ gfx::Rect bounds(0, 0, 100, 100);
+ scoped_ptr<aura::Window> window2(CreateWindow(bounds));
+ scoped_ptr<aura::Window> window1(CreateWindow(bounds));
+ scoped_ptr<aura::Window> window0(CreateWindow(bounds));
+ base::string16 window2_title = base::UTF8ToUTF16("Highway to test");
+ base::string16 window1_title = base::UTF8ToUTF16("For those about to test");
+ base::string16 window0_title = base::UTF8ToUTF16("We salute you");
+ window0->SetTitle(window0_title);
+ window1->SetTitle(window1_title);
+ window2->SetTitle(window2_title);
+ ToggleOverview();
+ EXPECT_FALSE(selection_widget_active());
+ EXPECT_FALSE(showing_filter_widget());
+ FilterItems("Test");
+
+ // The selection widget should appear when filtering starts, and should be
+ // selecting the first matching window.
+ EXPECT_TRUE(selection_widget_active());
+ EXPECT_TRUE(showing_filter_widget());
+ EXPECT_EQ(GetSelectedWindow(), window1.get());
+
+ // Window 0 has no "test" on it so it should be the only dimmed item.
+ std::vector<WindowSelectorItem*> items = GetWindowItemsForRoot(0);
+ EXPECT_TRUE(items[0]->dimmed());
+ EXPECT_FALSE(items[1]->dimmed());
+ EXPECT_FALSE(items[2]->dimmed());
+
+ // No items match the search.
+ FilterItems("I'm testing 'n testing");
+ EXPECT_TRUE(items[0]->dimmed());
+ EXPECT_TRUE(items[1]->dimmed());
+ EXPECT_TRUE(items[2]->dimmed());
+
+ // All the items should match the empty string. The filter widget should also
+ // disappear.
+ FilterItems("");
+ EXPECT_FALSE(showing_filter_widget());
+ EXPECT_FALSE(items[0]->dimmed());
+ EXPECT_FALSE(items[1]->dimmed());
+ EXPECT_FALSE(items[2]->dimmed());
+}
+
+// Tests selecting in the overview with dimmed and undimmed items.
+TEST_F(WindowSelectorTest, TextFilteringSelection) {
+ gfx::Rect bounds(0, 0, 100, 100);
+ scoped_ptr<aura::Window> window2(CreateWindow(bounds));
+ scoped_ptr<aura::Window> window1(CreateWindow(bounds));
+ scoped_ptr<aura::Window> window0(CreateWindow(bounds));
+ base::string16 window2_title = base::UTF8ToUTF16("Rock and roll");
+ base::string16 window1_title = base::UTF8ToUTF16("Rock and");
+ base::string16 window0_title = base::UTF8ToUTF16("Rock");
+ window0->SetTitle(window0_title);
+ window1->SetTitle(window1_title);
+ window2->SetTitle(window2_title);
+ ToggleOverview();
+ SendKey(ui::VKEY_RIGHT);
+ EXPECT_TRUE(selection_widget_active());
+ EXPECT_EQ(GetSelectedWindow(), window0.get());
+
+ // Dim the first item, the selection should jump to the next item.
+ std::vector<WindowSelectorItem*> items = GetWindowItemsForRoot(0);
+ FilterItems("Rock and");
+ EXPECT_EQ(GetSelectedWindow(), window1.get());
+
+ // Cycle the selection, the dimmed window should not be selected.
+ SendKey(ui::VKEY_RIGHT);
+ EXPECT_EQ(GetSelectedWindow(), window2.get());
+ SendKey(ui::VKEY_RIGHT);
+ EXPECT_EQ(GetSelectedWindow(), window1.get());
+
+ // Dimming all the items should hide the selection widget.
+ FilterItems("Pop");
+ EXPECT_FALSE(selection_widget_active());
+
+ // Undimming one window should automatically select it.
+ FilterItems("Rock and roll");
+ EXPECT_EQ(GetSelectedWindow(), window2.get());
+}
+
+// Tests clicking on the desktop itself to cancel overview mode.
+TEST_F(WindowSelectorTest, CancelOverviewOnMouseClick) {
+ // Overview disabled by default.
+ EXPECT_FALSE(IsSelecting());
+
+ // Point and bounds selected so that they don't intersect. This causes
+ // events located at the point to be passed to DesktopBackgroundController,
+ // and not the window.
+ gfx::Point point_in_background_page(0, 0);
+ gfx::Rect bounds(10, 10, 100, 100);
+ scoped_ptr<aura::Window> window1(CreateWindow(bounds));
+ ui::test::EventGenerator& generator = GetEventGenerator();
+ // Move mouse to point in the background page. Sending an event here will pass
+ // it to the DesktopBackgroundController in both regular and overview mode.
+ generator.MoveMouseTo(point_in_background_page);
+
+ // Clicking on the background page while not in overview should not toggle
+ // overview.
+ generator.ClickLeftButton();
+ EXPECT_FALSE(IsSelecting());
+
+ // Switch to overview mode.
+ ToggleOverview();
+ ASSERT_TRUE(IsSelecting());
+
+ // Click should now exit overview mode.
+ generator.ClickLeftButton();
+ EXPECT_FALSE(IsSelecting());
+}
+
+// Tests tapping on the desktop itself to cancel overview mode.
+TEST_F(WindowSelectorTest, CancelOverviewOnTap) {
+ // Overview disabled by default.
+ EXPECT_FALSE(IsSelecting());
+
+ // Point and bounds selected so that they don't intersect. This causes
+ // events located at the point to be passed to DesktopBackgroundController,
+ // and not the window.
+ gfx::Point point_in_background_page(0, 0);
+ gfx::Rect bounds(10, 10, 100, 100);
+ scoped_ptr<aura::Window> window1(CreateWindow(bounds));
+ ui::test::EventGenerator& generator = GetEventGenerator();
+
+ // Tapping on the background page while not in overview should not toggle
+ // overview.
+ generator.GestureTapAt(point_in_background_page);
+ EXPECT_FALSE(IsSelecting());
+
+ // Switch to overview mode.
+ ToggleOverview();
+ ASSERT_TRUE(IsSelecting());
+
+ // Tap should now exit overview mode.
+ generator.GestureTapAt(point_in_background_page);
+ EXPECT_FALSE(IsSelecting());
+}
+
} // namespace ash