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