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/shelf/shelf_window_watcher.h"
6
7#include "ash/ash_switches.h"
8#include "ash/shelf/shelf_item_types.h"
9#include "ash/shelf/shelf_model.h"
10#include "ash/shelf/shelf_util.h"
11#include "ash/shell.h"
12#include "ash/shell_window_ids.h"
13#include "ash/test/ash_test_base.h"
14#include "ash/test/shell_test_api.h"
15#include "ash/wm/window_resizer.h"
16#include "ash/wm/window_state.h"
17#include "ash/wm/window_util.h"
18#include "base/command_line.h"
19#include "ui/aura/client/aura_constants.h"
20#include "ui/aura/window.h"
21#include "ui/base/hit_test.h"
22
23namespace ash {
24
25class ShelfWindowWatcherTest : public test::AshTestBase {
26 public:
27  ShelfWindowWatcherTest() : model_(NULL) {}
28  virtual ~ShelfWindowWatcherTest() {}
29
30  virtual void SetUp() OVERRIDE {
31    test::AshTestBase::SetUp();
32    model_ = test::ShellTestApi(Shell::GetInstance()).shelf_model();
33  }
34
35  virtual void TearDown() OVERRIDE {
36    model_ = NULL;
37    test::AshTestBase::TearDown();
38  }
39
40  ShelfID CreateShelfItem(aura::Window* window) {
41    ShelfID id = model_->next_id();
42    ShelfItemDetails item_details;
43    item_details.type = TYPE_PLATFORM_APP;
44    SetShelfItemDetailsForWindow(window, item_details);
45    return id;
46  }
47
48 protected:
49  ShelfModel* model_;
50
51 private:
52  DISALLOW_COPY_AND_ASSIGN(ShelfWindowWatcherTest);
53};
54
55TEST_F(ShelfWindowWatcherTest, CreateAndRemoveShelfItem) {
56  // ShelfModel only has an APP_LIST item.
57  EXPECT_EQ(1, model_->item_count());
58
59  scoped_ptr<aura::Window> w1(CreateTestWindowInShellWithId(0));
60  scoped_ptr<aura::Window> w2(CreateTestWindowInShellWithId(0));
61
62  // Create a ShelfItem for w1.
63  ShelfID id_w1 = CreateShelfItem(w1.get());
64  EXPECT_EQ(2, model_->item_count());
65
66  int index_w1 = model_->ItemIndexByID(id_w1);
67  EXPECT_EQ(STATUS_RUNNING, model_->items()[index_w1].status);
68
69  // Create a ShelfItem for w2.
70  ShelfID id_w2 = CreateShelfItem(w2.get());
71  EXPECT_EQ(3, model_->item_count());
72
73  int index_w2 = model_->ItemIndexByID(id_w2);
74  EXPECT_EQ(STATUS_RUNNING, model_->items()[index_w2].status);
75
76  // ShelfItem is removed when assoicated window is destroyed.
77  ClearShelfItemDetailsForWindow(w1.get());
78  EXPECT_EQ(2, model_->item_count());
79  ClearShelfItemDetailsForWindow(w2.get());
80  EXPECT_EQ(1, model_->item_count());
81  // Clears twice doesn't do anything.
82  ClearShelfItemDetailsForWindow(w2.get());
83  EXPECT_EQ(1, model_->item_count());
84
85}
86
87TEST_F(ShelfWindowWatcherTest, ActivateWindow) {
88  // ShelfModel only have APP_LIST item.
89  EXPECT_EQ(1, model_->item_count());
90  scoped_ptr<aura::Window> w1(CreateTestWindowInShellWithId(0));
91  scoped_ptr<aura::Window> w2(CreateTestWindowInShellWithId(0));
92
93  // Create a ShelfItem for w1.
94  ShelfID id_w1 = CreateShelfItem(w1.get());
95  EXPECT_EQ(2, model_->item_count());
96  int index_w1 = model_->ItemIndexByID(id_w1);
97  EXPECT_EQ(STATUS_RUNNING, model_->items()[index_w1].status);
98
99  // Create a ShelfItem for w2.
100  ShelfID id_w2 = CreateShelfItem(w2.get());
101  EXPECT_EQ(3, model_->item_count());
102  int index_w2 = model_->ItemIndexByID(id_w2);
103  EXPECT_EQ(STATUS_RUNNING, model_->items()[index_w1].status);
104  EXPECT_EQ(STATUS_RUNNING, model_->items()[index_w2].status);
105
106  // ShelfItem for w1 is active when w1 is activated.
107  wm::ActivateWindow(w1.get());
108  EXPECT_EQ(STATUS_ACTIVE, model_->items()[index_w1].status);
109
110  // ShelfItem for w2 is active state when w2 is activated.
111  wm::ActivateWindow(w2.get());
112  EXPECT_EQ(STATUS_RUNNING, model_->items()[index_w1].status);
113  EXPECT_EQ(STATUS_ACTIVE, model_->items()[index_w2].status);
114}
115
116TEST_F(ShelfWindowWatcherTest, UpdateWindowProperty) {
117  // ShelfModel only has an APP_LIST item.
118  EXPECT_EQ(1, model_->item_count());
119
120  scoped_ptr<aura::Window> window(CreateTestWindowInShellWithId(0));
121
122  // Create a ShelfItem for |window|.
123  ShelfID id = CreateShelfItem(window.get());
124  EXPECT_EQ(2, model_->item_count());
125
126  int index = model_->ItemIndexByID(id);
127  EXPECT_EQ(STATUS_RUNNING, model_->items()[index].status);
128
129  // Update ShelfItem for |window|.
130  ShelfItemDetails details;
131  details.type = TYPE_PLATFORM_APP;
132
133  SetShelfItemDetailsForWindow(window.get(), details);
134  // No new item is created after updating a launcher item.
135  EXPECT_EQ(2, model_->item_count());
136  // index and id are not changed after updating a launcher item.
137  EXPECT_EQ(index, model_->ItemIndexByID(id));
138  EXPECT_EQ(id, model_->items()[index].id);
139}
140
141TEST_F(ShelfWindowWatcherTest, MaximizeAndRestoreWindow) {
142  // ShelfModel only has an APP_LIST item.
143  EXPECT_EQ(1, model_->item_count());
144
145  scoped_ptr<aura::Window> window(CreateTestWindowInShellWithId(0));
146  wm::WindowState* window_state = wm::GetWindowState(window.get());
147
148  // Create a ShelfItem for |window|.
149  ShelfID id = CreateShelfItem(window.get());
150  EXPECT_EQ(2, model_->item_count());
151
152  int index = model_->ItemIndexByID(id);
153  EXPECT_EQ(STATUS_RUNNING, model_->items()[index].status);
154
155  // Maximize window |window|.
156  EXPECT_FALSE(window_state->IsMaximized());
157  window_state->Maximize();
158  EXPECT_TRUE(window_state->IsMaximized());
159  // No new item is created after maximizing a window |window|.
160  EXPECT_EQ(2, model_->item_count());
161  // index and id are not changed after maximizing a window |window|.
162  EXPECT_EQ(index, model_->ItemIndexByID(id));
163  EXPECT_EQ(id, model_->items()[index].id);
164
165  // Restore window |window|.
166  window_state->Restore();
167  EXPECT_FALSE(window_state->IsMaximized());
168  // No new item is created after restoring a window |window|.
169  EXPECT_EQ(2, model_->item_count());
170  // Index and id are not changed after maximizing a window |window|.
171  EXPECT_EQ(index, model_->ItemIndexByID(id));
172  EXPECT_EQ(id, model_->items()[index].id);
173}
174
175// Check that an item is removed when its associated Window is re-parented.
176TEST_F(ShelfWindowWatcherTest, ReparentWindow) {
177  // ShelfModel only has an APP_LIST item.
178  EXPECT_EQ(1, model_->item_count());
179
180  scoped_ptr<aura::Window> window(CreateTestWindowInShellWithId(0));
181  window->set_owned_by_parent(false);
182
183  // Create a ShelfItem for |window|.
184  ShelfID id = CreateShelfItem(window.get());
185  EXPECT_EQ(2, model_->item_count());
186
187  int index = model_->ItemIndexByID(id);
188  EXPECT_EQ(STATUS_RUNNING, model_->items()[index].status);
189
190  aura::Window* root_window = window->GetRootWindow();
191  aura::Window* default_container = Shell::GetContainer(
192      root_window,
193      kShellWindowId_DefaultContainer);
194  EXPECT_EQ(default_container, window->parent());
195
196  aura::Window* new_parent = Shell::GetContainer(
197      root_window,
198      kShellWindowId_PanelContainer);
199
200  // Check |window|'s item is removed when it is re-parented to |new_parent|
201  // which is not default container.
202  new_parent->AddChild(window.get());
203  EXPECT_EQ(1, model_->item_count());
204
205  // Check |window|'s item is added when it is re-parented to
206  // |default_container|.
207  default_container->AddChild(window.get());
208  EXPECT_EQ(2, model_->item_count());
209}
210
211// Check |window|'s item is not changed during the dragging.
212// TODO(simonhong): Add a test for removing a Window during the dragging.
213TEST_F(ShelfWindowWatcherTest, DragWindow) {
214  // ShelfModel only has an APP_LIST item.
215  EXPECT_EQ(1, model_->item_count());
216
217  scoped_ptr<aura::Window> window(CreateTestWindowInShellWithId(0));
218
219  // Create a ShelfItem for |window|.
220  ShelfID id = CreateShelfItem(window.get());
221  EXPECT_EQ(2, model_->item_count());
222
223  int index = model_->ItemIndexByID(id);
224  EXPECT_EQ(STATUS_RUNNING, model_->items()[index].status);
225
226  // Simulate dragging of |window| and check its item is not changed.
227  scoped_ptr<WindowResizer> resizer(
228      CreateWindowResizer(window.get(),
229                          gfx::Point(),
230                          HTCAPTION,
231                          aura::client::WINDOW_MOVE_SOURCE_MOUSE));
232  ASSERT_TRUE(resizer.get());
233  resizer->Drag(gfx::Point(50, 50), 0);
234  resizer->CompleteDrag();
235
236  //Index and id are not changed after dragging a |window|.
237  EXPECT_EQ(index, model_->ItemIndexByID(id));
238  EXPECT_EQ(id, model_->items()[index].id);
239}
240
241// Check |window|'s item is removed when it is re-parented not to default
242// container during the dragging.
243TEST_F(ShelfWindowWatcherTest, ReparentWindowDuringTheDragging) {
244  // ShelfModel only has an APP_LIST item.
245  EXPECT_EQ(1, model_->item_count());
246
247  scoped_ptr<aura::Window> window(CreateTestWindowInShellWithId(0));
248  window->set_owned_by_parent(false);
249
250  // Create a ShelfItem for |window|.
251  ShelfID id = CreateShelfItem(window.get());
252  EXPECT_EQ(2, model_->item_count());
253  int index = model_->ItemIndexByID(id);
254  EXPECT_EQ(STATUS_RUNNING, model_->items()[index].status);
255
256  aura::Window* root_window = window->GetRootWindow();
257  aura::Window* default_container = Shell::GetContainer(
258      root_window,
259      kShellWindowId_DefaultContainer);
260  EXPECT_EQ(default_container, window->parent());
261
262  aura::Window* new_parent = Shell::GetContainer(
263      root_window,
264      kShellWindowId_PanelContainer);
265
266  // Simulate re-parenting to |new_parent| during the dragging.
267  {
268    scoped_ptr<WindowResizer> resizer(
269        CreateWindowResizer(window.get(),
270                            gfx::Point(),
271                            HTCAPTION,
272                            aura::client::WINDOW_MOVE_SOURCE_MOUSE));
273    ASSERT_TRUE(resizer.get());
274    resizer->Drag(gfx::Point(50, 50), 0);
275    resizer->CompleteDrag();
276    EXPECT_EQ(2, model_->item_count());
277
278    // Item should be removed when |window| is re-parented not to default
279    // container before fininshing the dragging.
280    EXPECT_TRUE(wm::GetWindowState(window.get())->is_dragged());
281    new_parent->AddChild(window.get());
282    EXPECT_EQ(1, model_->item_count());
283  }
284  EXPECT_FALSE(wm::GetWindowState(window.get())->is_dragged());
285  EXPECT_EQ(1, model_->item_count());
286}
287
288}  // namespace ash
289