| OLD | NEW |
| (Empty) |
| 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/common/shelf/shelf_window_watcher.h" | |
| 6 | |
| 7 #include "ash/common/session/session_state_delegate.h" | |
| 8 #include "ash/common/shelf/shelf_item_types.h" | |
| 9 #include "ash/common/shelf/shelf_model.h" | |
| 10 #include "ash/common/wm/window_resizer.h" | |
| 11 #include "ash/common/wm/window_state.h" | |
| 12 #include "ash/common/wm_shell.h" | |
| 13 #include "ash/common/wm_window.h" | |
| 14 #include "ash/public/cpp/shell_window_ids.h" | |
| 15 #include "ash/public/cpp/window_properties.h" | |
| 16 #include "ash/root_window_controller.h" | |
| 17 #include "ash/test/ash_test_base.h" | |
| 18 #include "ui/base/hit_test.h" | |
| 19 #include "ui/views/widget/widget.h" | |
| 20 | |
| 21 namespace ash { | |
| 22 | |
| 23 class ShelfWindowWatcherTest : public test::AshTestBase { | |
| 24 public: | |
| 25 ShelfWindowWatcherTest() : model_(nullptr) {} | |
| 26 ~ShelfWindowWatcherTest() override {} | |
| 27 | |
| 28 void SetUp() override { | |
| 29 test::AshTestBase::SetUp(); | |
| 30 model_ = WmShell::Get()->shelf_model(); | |
| 31 } | |
| 32 | |
| 33 void TearDown() override { | |
| 34 model_ = nullptr; | |
| 35 test::AshTestBase::TearDown(); | |
| 36 } | |
| 37 | |
| 38 static ShelfID CreateShelfItem(WmWindow* window) { | |
| 39 ShelfID id = WmShell::Get()->shelf_model()->next_id(); | |
| 40 window->aura_window()->SetProperty(kShelfItemTypeKey, | |
| 41 static_cast<int32_t>(TYPE_DIALOG)); | |
| 42 return id; | |
| 43 } | |
| 44 | |
| 45 protected: | |
| 46 ShelfModel* model_; | |
| 47 | |
| 48 private: | |
| 49 DISALLOW_COPY_AND_ASSIGN(ShelfWindowWatcherTest); | |
| 50 }; | |
| 51 | |
| 52 // Ensure shelf items are added and removed as windows are opened and closed. | |
| 53 TEST_F(ShelfWindowWatcherTest, OpenAndClose) { | |
| 54 // ShelfModel only has an APP_LIST item. | |
| 55 EXPECT_EQ(1, model_->item_count()); | |
| 56 | |
| 57 // Adding windows with valid ShelfItemType properties adds shelf items. | |
| 58 std::unique_ptr<views::Widget> widget1 = | |
| 59 CreateTestWidget(nullptr, kShellWindowId_DefaultContainer, gfx::Rect()); | |
| 60 CreateShelfItem(WmWindow::Get(widget1->GetNativeWindow())); | |
| 61 EXPECT_EQ(2, model_->item_count()); | |
| 62 std::unique_ptr<views::Widget> widget2 = | |
| 63 CreateTestWidget(nullptr, kShellWindowId_DefaultContainer, gfx::Rect()); | |
| 64 CreateShelfItem(WmWindow::Get(widget2->GetNativeWindow())); | |
| 65 EXPECT_EQ(3, model_->item_count()); | |
| 66 | |
| 67 // Each ShelfItem is removed when the associated window is destroyed. | |
| 68 widget1.reset(); | |
| 69 EXPECT_EQ(2, model_->item_count()); | |
| 70 widget2.reset(); | |
| 71 EXPECT_EQ(1, model_->item_count()); | |
| 72 } | |
| 73 | |
| 74 TEST_F(ShelfWindowWatcherTest, CreateAndRemoveShelfItemProperties) { | |
| 75 // TODO: investigate failure in mash. http://crbug.com/695562. | |
| 76 if (WmShell::Get()->IsRunningInMash()) | |
| 77 return; | |
| 78 | |
| 79 // ShelfModel only has an APP_LIST item. | |
| 80 EXPECT_EQ(1, model_->item_count()); | |
| 81 | |
| 82 // Creating windows without a valid ShelfItemType does not add items. | |
| 83 std::unique_ptr<views::Widget> widget1 = | |
| 84 CreateTestWidget(nullptr, kShellWindowId_DefaultContainer, gfx::Rect()); | |
| 85 WmWindow* window1 = WmWindow::Get(widget1->GetNativeWindow()); | |
| 86 std::unique_ptr<views::Widget> widget2 = | |
| 87 CreateTestWidget(nullptr, kShellWindowId_DefaultContainer, gfx::Rect()); | |
| 88 WmWindow* window2 = WmWindow::Get(widget2->GetNativeWindow()); | |
| 89 EXPECT_EQ(1, model_->item_count()); | |
| 90 | |
| 91 // Create a ShelfItem for the first window. | |
| 92 ShelfID id_w1 = CreateShelfItem(window1); | |
| 93 EXPECT_EQ(2, model_->item_count()); | |
| 94 | |
| 95 int index_w1 = model_->ItemIndexByID(id_w1); | |
| 96 EXPECT_EQ(STATUS_RUNNING, model_->items()[index_w1].status); | |
| 97 | |
| 98 // Create a ShelfItem for the second window. | |
| 99 ShelfID id_w2 = CreateShelfItem(window2); | |
| 100 EXPECT_EQ(3, model_->item_count()); | |
| 101 | |
| 102 int index_w2 = model_->ItemIndexByID(id_w2); | |
| 103 EXPECT_EQ(STATUS_ACTIVE, model_->items()[index_w2].status); | |
| 104 | |
| 105 // ShelfItem is removed when the item type window property is cleared. | |
| 106 window1->aura_window()->SetProperty(kShelfItemTypeKey, | |
| 107 static_cast<int32_t>(TYPE_UNDEFINED)); | |
| 108 EXPECT_EQ(2, model_->item_count()); | |
| 109 window2->aura_window()->SetProperty(kShelfItemTypeKey, | |
| 110 static_cast<int32_t>(TYPE_UNDEFINED)); | |
| 111 EXPECT_EQ(1, model_->item_count()); | |
| 112 // Clearing twice doesn't do anything. | |
| 113 window2->aura_window()->SetProperty(kShelfItemTypeKey, | |
| 114 static_cast<int32_t>(TYPE_UNDEFINED)); | |
| 115 EXPECT_EQ(1, model_->item_count()); | |
| 116 } | |
| 117 | |
| 118 TEST_F(ShelfWindowWatcherTest, ActivateWindow) { | |
| 119 // TODO: investigate failure in mash. http://crbug.com/695562. | |
| 120 if (WmShell::Get()->IsRunningInMash()) | |
| 121 return; | |
| 122 | |
| 123 // ShelfModel only have APP_LIST item. | |
| 124 EXPECT_EQ(1, model_->item_count()); | |
| 125 std::unique_ptr<views::Widget> widget1 = | |
| 126 CreateTestWidget(nullptr, kShellWindowId_DefaultContainer, gfx::Rect()); | |
| 127 WmWindow* window1 = WmWindow::Get(widget1->GetNativeWindow()); | |
| 128 std::unique_ptr<views::Widget> widget2 = | |
| 129 CreateTestWidget(nullptr, kShellWindowId_DefaultContainer, gfx::Rect()); | |
| 130 WmWindow* window2 = WmWindow::Get(widget2->GetNativeWindow()); | |
| 131 | |
| 132 // Create a ShelfItem for the first window. | |
| 133 ShelfID id_w1 = CreateShelfItem(window1); | |
| 134 EXPECT_EQ(2, model_->item_count()); | |
| 135 int index_w1 = model_->ItemIndexByID(id_w1); | |
| 136 EXPECT_EQ(STATUS_RUNNING, model_->items()[index_w1].status); | |
| 137 | |
| 138 // Create a ShelfItem for the second window. | |
| 139 ShelfID id_w2 = CreateShelfItem(window2); | |
| 140 EXPECT_EQ(3, model_->item_count()); | |
| 141 int index_w2 = model_->ItemIndexByID(id_w2); | |
| 142 EXPECT_EQ(STATUS_RUNNING, model_->items()[index_w1].status); | |
| 143 EXPECT_EQ(STATUS_ACTIVE, model_->items()[index_w2].status); | |
| 144 | |
| 145 // The ShelfItem for the first window is active when the window is activated. | |
| 146 widget1->Activate(); | |
| 147 EXPECT_EQ(STATUS_ACTIVE, model_->items()[index_w1].status); | |
| 148 EXPECT_EQ(STATUS_RUNNING, model_->items()[index_w2].status); | |
| 149 | |
| 150 // The ShelfItem for the second window is active when the window is activated. | |
| 151 widget2->Activate(); | |
| 152 EXPECT_EQ(STATUS_RUNNING, model_->items()[index_w1].status); | |
| 153 EXPECT_EQ(STATUS_ACTIVE, model_->items()[index_w2].status); | |
| 154 } | |
| 155 | |
| 156 TEST_F(ShelfWindowWatcherTest, UpdateWindowProperty) { | |
| 157 // TODO: investigate failure in mash. http://crbug.com/695562. | |
| 158 if (WmShell::Get()->IsRunningInMash()) | |
| 159 return; | |
| 160 | |
| 161 // ShelfModel only has an APP_LIST item. | |
| 162 EXPECT_EQ(1, model_->item_count()); | |
| 163 | |
| 164 std::unique_ptr<views::Widget> widget = | |
| 165 CreateTestWidget(nullptr, kShellWindowId_DefaultContainer, gfx::Rect()); | |
| 166 WmWindow* window = WmWindow::Get(widget->GetNativeWindow()); | |
| 167 | |
| 168 // Create a ShelfItem for |window|. | |
| 169 ShelfID id = CreateShelfItem(window); | |
| 170 EXPECT_EQ(2, model_->item_count()); | |
| 171 | |
| 172 int index = model_->ItemIndexByID(id); | |
| 173 EXPECT_EQ(STATUS_ACTIVE, model_->items()[index].status); | |
| 174 | |
| 175 // Update the ShelfItemType for |window|. | |
| 176 window->aura_window()->SetProperty(kShelfItemTypeKey, | |
| 177 static_cast<int32_t>(TYPE_APP)); | |
| 178 // No new item is created after updating a launcher item. | |
| 179 EXPECT_EQ(2, model_->item_count()); | |
| 180 // index and id are not changed after updating a launcher item. | |
| 181 EXPECT_EQ(index, model_->ItemIndexByID(id)); | |
| 182 EXPECT_EQ(id, model_->items()[index].id); | |
| 183 } | |
| 184 | |
| 185 TEST_F(ShelfWindowWatcherTest, MaximizeAndRestoreWindow) { | |
| 186 // TODO: investigate failure in mash. http://crbug.com/695562. | |
| 187 if (WmShell::Get()->IsRunningInMash()) | |
| 188 return; | |
| 189 | |
| 190 // ShelfModel only has an APP_LIST item. | |
| 191 EXPECT_EQ(1, model_->item_count()); | |
| 192 | |
| 193 std::unique_ptr<views::Widget> widget = | |
| 194 CreateTestWidget(nullptr, kShellWindowId_DefaultContainer, gfx::Rect()); | |
| 195 WmWindow* window = WmWindow::Get(widget->GetNativeWindow()); | |
| 196 wm::WindowState* window_state = window->GetWindowState(); | |
| 197 | |
| 198 // Create a ShelfItem for |window|. | |
| 199 ShelfID id = CreateShelfItem(window); | |
| 200 EXPECT_EQ(2, model_->item_count()); | |
| 201 | |
| 202 int index = model_->ItemIndexByID(id); | |
| 203 EXPECT_EQ(STATUS_ACTIVE, model_->items()[index].status); | |
| 204 | |
| 205 // Maximize window |window|. | |
| 206 EXPECT_FALSE(window_state->IsMaximized()); | |
| 207 window_state->Maximize(); | |
| 208 EXPECT_TRUE(window_state->IsMaximized()); | |
| 209 // No new item is created after maximizing a window |window|. | |
| 210 EXPECT_EQ(2, model_->item_count()); | |
| 211 // index and id are not changed after maximizing a window |window|. | |
| 212 EXPECT_EQ(index, model_->ItemIndexByID(id)); | |
| 213 EXPECT_EQ(id, model_->items()[index].id); | |
| 214 | |
| 215 // Restore window |window|. | |
| 216 window_state->Restore(); | |
| 217 EXPECT_FALSE(window_state->IsMaximized()); | |
| 218 // No new item is created after restoring a window |window|. | |
| 219 EXPECT_EQ(2, model_->item_count()); | |
| 220 // Index and id are not changed after maximizing a window |window|. | |
| 221 EXPECT_EQ(index, model_->ItemIndexByID(id)); | |
| 222 EXPECT_EQ(id, model_->items()[index].id); | |
| 223 } | |
| 224 | |
| 225 // Check that an item is maintained when its associated Window is docked. | |
| 226 TEST_F(ShelfWindowWatcherTest, DockWindow) { | |
| 227 // TODO: investigate failure in mash. http://crbug.com/695562. | |
| 228 if (WmShell::Get()->IsRunningInMash()) | |
| 229 return; | |
| 230 | |
| 231 // ShelfModel only has an APP_LIST item. | |
| 232 EXPECT_EQ(1, model_->item_count()); | |
| 233 | |
| 234 std::unique_ptr<views::Widget> widget = | |
| 235 CreateTestWidget(nullptr, kShellWindowId_DefaultContainer, gfx::Rect()); | |
| 236 WmWindow* window = WmWindow::Get(widget->GetNativeWindow()); | |
| 237 | |
| 238 // Create a ShelfItem for |window|. | |
| 239 ShelfID id = CreateShelfItem(window); | |
| 240 EXPECT_EQ(2, model_->item_count()); | |
| 241 | |
| 242 int index = model_->ItemIndexByID(id); | |
| 243 EXPECT_EQ(STATUS_ACTIVE, model_->items()[index].status); | |
| 244 | |
| 245 WmWindow* root_window = window->GetRootWindow(); | |
| 246 WmWindow* default_container = | |
| 247 root_window->GetChildByShellWindowId(kShellWindowId_DefaultContainer); | |
| 248 EXPECT_EQ(default_container, window->GetParent()); | |
| 249 | |
| 250 WmWindow* docked_container = | |
| 251 root_window->GetChildByShellWindowId(kShellWindowId_DockedContainer); | |
| 252 | |
| 253 // Check |window|'s item is not removed when it is re-parented to the dock. | |
| 254 docked_container->AddChild(window); | |
| 255 EXPECT_EQ(docked_container, window->GetParent()); | |
| 256 EXPECT_EQ(2, model_->item_count()); | |
| 257 | |
| 258 // The shelf item is removed when the window is closed, even if it is in the | |
| 259 // docked container at the time. | |
| 260 widget.reset(); | |
| 261 EXPECT_EQ(1, model_->item_count()); | |
| 262 } | |
| 263 | |
| 264 // Check |window|'s item is not changed during the dragging. | |
| 265 // TODO(simonhong): Add a test for removing a Window during the dragging. | |
| 266 TEST_F(ShelfWindowWatcherTest, DragWindow) { | |
| 267 // TODO: investigate failure in mash. http://crbug.com/695562. | |
| 268 if (WmShell::Get()->IsRunningInMash()) | |
| 269 return; | |
| 270 | |
| 271 // ShelfModel only has an APP_LIST item. | |
| 272 EXPECT_EQ(1, model_->item_count()); | |
| 273 | |
| 274 std::unique_ptr<views::Widget> widget = | |
| 275 CreateTestWidget(nullptr, kShellWindowId_DefaultContainer, gfx::Rect()); | |
| 276 WmWindow* window = WmWindow::Get(widget->GetNativeWindow()); | |
| 277 | |
| 278 // Create a ShelfItem for |window|. | |
| 279 ShelfID id = CreateShelfItem(window); | |
| 280 EXPECT_EQ(2, model_->item_count()); | |
| 281 | |
| 282 int index = model_->ItemIndexByID(id); | |
| 283 EXPECT_EQ(STATUS_ACTIVE, model_->items()[index].status); | |
| 284 | |
| 285 // Simulate dragging of |window| and check its item is not changed. | |
| 286 std::unique_ptr<WindowResizer> resizer(CreateWindowResizer( | |
| 287 window, gfx::Point(), HTCAPTION, aura::client::WINDOW_MOVE_SOURCE_MOUSE)); | |
| 288 ASSERT_TRUE(resizer.get()); | |
| 289 resizer->Drag(gfx::Point(50, 50), 0); | |
| 290 resizer->CompleteDrag(); | |
| 291 | |
| 292 // Index and id are not changed after dragging a |window|. | |
| 293 EXPECT_EQ(index, model_->ItemIndexByID(id)); | |
| 294 EXPECT_EQ(id, model_->items()[index].id); | |
| 295 } | |
| 296 | |
| 297 // Ensure shelf items are added and removed as panels are opened and closed. | |
| 298 TEST_F(ShelfWindowWatcherTest, PanelWindow) { | |
| 299 // TODO: investigate failure in mash. http://crbug.com/695562. | |
| 300 if (WmShell::Get()->IsRunningInMash()) | |
| 301 return; | |
| 302 | |
| 303 // ShelfModel only has an APP_LIST item. | |
| 304 EXPECT_EQ(1, model_->item_count()); | |
| 305 | |
| 306 // Adding windows with valid ShelfItemType properties adds shelf items. | |
| 307 std::unique_ptr<views::Widget> widget1 = | |
| 308 CreateTestWidget(nullptr, kShellWindowId_PanelContainer, gfx::Rect()); | |
| 309 WmWindow* window1 = WmWindow::Get(widget1->GetNativeWindow()); | |
| 310 window1->aura_window()->SetProperty(kShelfItemTypeKey, | |
| 311 static_cast<int32_t>(TYPE_APP_PANEL)); | |
| 312 EXPECT_EQ(2, model_->item_count()); | |
| 313 std::unique_ptr<views::Widget> widget2 = | |
| 314 CreateTestWidget(nullptr, kShellWindowId_DefaultContainer, gfx::Rect()); | |
| 315 WmWindow* window2 = WmWindow::Get(widget2->GetNativeWindow()); | |
| 316 window2->aura_window()->SetProperty(kShelfItemTypeKey, | |
| 317 static_cast<int32_t>(TYPE_APP_PANEL)); | |
| 318 EXPECT_EQ(3, model_->item_count()); | |
| 319 | |
| 320 // Create a panel-type widget to mimic Chrome's app panel windows. | |
| 321 views::Widget panel_widget; | |
| 322 views::Widget::InitParams panel_params(views::Widget::InitParams::TYPE_PANEL); | |
| 323 panel_params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; | |
| 324 WmShell::Get() | |
| 325 ->GetPrimaryRootWindow() | |
| 326 ->GetRootWindowController() | |
| 327 ->ConfigureWidgetInitParamsForContainer( | |
| 328 &panel_widget, kShellWindowId_PanelContainer, &panel_params); | |
| 329 panel_widget.Init(panel_params); | |
| 330 panel_widget.Show(); | |
| 331 WmWindow* panel_window = WmWindow::Get(panel_widget.GetNativeWindow()); | |
| 332 panel_window->aura_window()->SetProperty( | |
| 333 kShelfItemTypeKey, static_cast<int32_t>(TYPE_APP_PANEL)); | |
| 334 EXPECT_EQ(4, model_->item_count()); | |
| 335 | |
| 336 // Each ShelfItem is removed when the associated window is destroyed. | |
| 337 panel_widget.CloseNow(); | |
| 338 EXPECT_EQ(3, model_->item_count()); | |
| 339 widget2.reset(); | |
| 340 EXPECT_EQ(2, model_->item_count()); | |
| 341 widget1.reset(); | |
| 342 EXPECT_EQ(1, model_->item_count()); | |
| 343 } | |
| 344 | |
| 345 TEST_F(ShelfWindowWatcherTest, DontCreateShelfEntriesForChildWindows) { | |
| 346 const int initial_item_count = model_->item_count(); | |
| 347 | |
| 348 WmWindow* window = WmShell::Get()->NewWindow(ui::wm::WINDOW_TYPE_NORMAL, | |
| 349 ui::LAYER_NOT_DRAWN); | |
| 350 window->aura_window()->SetProperty(kShelfItemTypeKey, | |
| 351 static_cast<int32_t>(TYPE_APP)); | |
| 352 WmShell::Get() | |
| 353 ->GetPrimaryRootWindow() | |
| 354 ->GetChildByShellWindowId(kShellWindowId_DefaultContainer) | |
| 355 ->AddChild(window); | |
| 356 window->Show(); | |
| 357 EXPECT_EQ(initial_item_count + 1, model_->item_count()); | |
| 358 | |
| 359 WmWindow* child_window = WmShell::Get()->NewWindow(ui::wm::WINDOW_TYPE_NORMAL, | |
| 360 ui::LAYER_NOT_DRAWN); | |
| 361 child_window->aura_window()->SetProperty(kShelfItemTypeKey, | |
| 362 static_cast<int32_t>(TYPE_APP)); | |
| 363 window->AddChild(child_window); | |
| 364 child_window->Show(); | |
| 365 // |child_window| should not result in adding a new entry. | |
| 366 EXPECT_EQ(initial_item_count + 1, model_->item_count()); | |
| 367 | |
| 368 child_window->Destroy(); | |
| 369 window->Destroy(); | |
| 370 EXPECT_EQ(initial_item_count, model_->item_count()); | |
| 371 } | |
| 372 | |
| 373 // Ensures ShelfWindowWatcher supports windows opened prior to session start. | |
| 374 using ShelfWindowWatcherSessionStartTest = test::NoSessionAshTestBase; | |
| 375 TEST_F(ShelfWindowWatcherSessionStartTest, PreExistingWindow) { | |
| 376 ShelfModel* model = WmShell::Get()->shelf_model(); | |
| 377 ASSERT_FALSE( | |
| 378 WmShell::Get()->GetSessionStateDelegate()->IsActiveUserSessionStarted()); | |
| 379 | |
| 380 // ShelfModel only has an APP_LIST item. | |
| 381 EXPECT_EQ(1, model->item_count()); | |
| 382 | |
| 383 // Construct a window that should get a shelf item once the session starts. | |
| 384 std::unique_ptr<views::Widget> widget = | |
| 385 CreateTestWidget(nullptr, kShellWindowId_DefaultContainer, gfx::Rect()); | |
| 386 WmWindow* window = WmWindow::Get(widget->GetNativeWindow()); | |
| 387 ShelfWindowWatcherTest::CreateShelfItem(window); | |
| 388 EXPECT_EQ(1, model->item_count()); | |
| 389 | |
| 390 // Start the test user session; ShelfWindowWatcher will find the open window. | |
| 391 SetSessionStarted(true); | |
| 392 EXPECT_EQ(2, model->item_count()); | |
| 393 } | |
| 394 | |
| 395 } // namespace ash | |
| OLD | NEW |