1// Copyright (c) 2012 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 "ui/views/corewm/window_modality_controller.h"
6
7#include "ash/shell.h"
8#include "ash/test/ash_test_base.h"
9#include "ash/wm/window_util.h"
10#include "ui/aura/client/aura_constants.h"
11#include "ui/aura/root_window.h"
12#include "ui/aura/test/event_generator.h"
13#include "ui/aura/test/test_window_delegate.h"
14#include "ui/aura/test/test_windows.h"
15#include "ui/aura/window.h"
16#include "ui/base/ui_base_types.h"
17#include "ui/views/test/capture_tracking_view.h"
18#include "ui/views/test/child_modal_window.h"
19#include "ui/views/widget/widget.h"
20
21namespace ash {
22namespace internal {
23
24typedef test::AshTestBase WindowModalityControllerTest;
25
26namespace {
27
28bool ValidateStacking(aura::Window* parent, int ids[], int count) {
29  for (int i = 0; i < count; ++i) {
30    if (parent->children().at(i)->id() != ids[i])
31      return false;
32  }
33  return true;
34}
35
36}  // namespace
37
38// Creates three windows, w1, w11, and w12. w11 is a non-modal transient, w12 is
39// a modal transient.
40// Validates:
41// - it should be possible to activate w12 even when w11 is open.
42// - activating w1 activates w12 and updates stacking order appropriately.
43// - closing a window passes focus up the stack.
44TEST_F(WindowModalityControllerTest, BasicActivation) {
45  aura::test::TestWindowDelegate d;
46  scoped_ptr<aura::Window> w1(
47      CreateTestWindowInShellWithDelegate(&d, -1, gfx::Rect()));
48  scoped_ptr<aura::Window> w11(
49      CreateTestWindowInShellWithDelegate(&d, -11, gfx::Rect()));
50  scoped_ptr<aura::Window> w12(
51      CreateTestWindowInShellWithDelegate(&d, -12, gfx::Rect()));
52
53  w1->AddTransientChild(w11.get());
54  wm::ActivateWindow(w1.get());
55  EXPECT_TRUE(wm::IsActiveWindow(w1.get()));
56  wm::ActivateWindow(w11.get());
57  EXPECT_TRUE(wm::IsActiveWindow(w11.get()));
58
59  w12->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_WINDOW);
60  w1->AddTransientChild(w12.get());
61  wm::ActivateWindow(w12.get());
62  EXPECT_TRUE(wm::IsActiveWindow(w12.get()));
63
64  wm::ActivateWindow(w11.get());
65  EXPECT_TRUE(wm::IsActiveWindow(w11.get()));
66
67  int check1[] = { -1, -12, -11 };
68  EXPECT_TRUE(ValidateStacking(w1->parent(), check1, arraysize(check1)));
69
70  wm::ActivateWindow(w1.get());
71  EXPECT_TRUE(wm::IsActiveWindow(w12.get()));
72  // Transient children are always stacked above their transient parent, which
73  // is why this order is not -11, -1, -12.
74  int check2[] = { -1, -11, -12 };
75  EXPECT_TRUE(ValidateStacking(w1->parent(), check2, arraysize(check2)));
76
77  w12.reset();
78  EXPECT_TRUE(wm::IsActiveWindow(w11.get()));
79  w11.reset();
80  EXPECT_TRUE(wm::IsActiveWindow(w1.get()));
81}
82
83// Create two toplevel windows w1 and w2, and nest two modals w11 and w111 below
84// w1.
85// Validates:
86// - activating w1 while w11/w111 is showing always activates most deeply nested
87//   descendant.
88// - closing a window passes focus up the stack.
89TEST_F(WindowModalityControllerTest, NestedModals) {
90  aura::test::TestWindowDelegate d;
91  scoped_ptr<aura::Window> w1(
92      CreateTestWindowInShellWithDelegate(&d, -1, gfx::Rect()));
93  scoped_ptr<aura::Window> w11(
94      CreateTestWindowInShellWithDelegate(&d, -11, gfx::Rect()));
95  scoped_ptr<aura::Window> w111(
96      CreateTestWindowInShellWithDelegate(&d, -111, gfx::Rect()));
97  scoped_ptr<aura::Window> w2(
98      CreateTestWindowInShellWithDelegate(&d, -2, gfx::Rect()));
99
100  w1->AddTransientChild(w11.get());
101  w11->AddTransientChild(w111.get());
102
103  wm::ActivateWindow(w1.get());
104  EXPECT_TRUE(wm::IsActiveWindow(w1.get()));
105  wm::ActivateWindow(w2.get());
106  EXPECT_TRUE(wm::IsActiveWindow(w2.get()));
107
108  // Set up modality.
109  w11->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_WINDOW);
110  w111->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_WINDOW);
111
112  wm::ActivateWindow(w1.get());
113  EXPECT_TRUE(wm::IsActiveWindow(w111.get()));
114  int check1[] = { -2, -1, -11, -111 };
115  EXPECT_TRUE(ValidateStacking(w1->parent(), check1, arraysize(check1)));
116
117  wm::ActivateWindow(w11.get());
118  EXPECT_TRUE(wm::IsActiveWindow(w111.get()));
119  EXPECT_TRUE(ValidateStacking(w1->parent(), check1, arraysize(check1)));
120
121  wm::ActivateWindow(w111.get());
122  EXPECT_TRUE(wm::IsActiveWindow(w111.get()));
123  EXPECT_TRUE(ValidateStacking(w1->parent(), check1, arraysize(check1)));
124
125  wm::ActivateWindow(w2.get());
126  EXPECT_TRUE(wm::IsActiveWindow(w2.get()));
127  int check2[] = { -1, -11, -111, -2 };
128  EXPECT_TRUE(ValidateStacking(w1->parent(), check2, arraysize(check2)));
129
130  w2.reset();
131  EXPECT_TRUE(wm::IsActiveWindow(w111.get()));
132  w111.reset();
133  EXPECT_TRUE(wm::IsActiveWindow(w11.get()));
134  w11.reset();
135  EXPECT_TRUE(wm::IsActiveWindow(w1.get()));
136}
137
138// Create two toplevel windows w1 and w2, and nest two modals w11 and w111 below
139// w1.
140// Validates:
141// - destroying w11 while w111 is focused activates w1.
142TEST_F(WindowModalityControllerTest, NestedModalsOuterClosed) {
143  aura::test::TestWindowDelegate d;
144  scoped_ptr<aura::Window> w1(
145      CreateTestWindowInShellWithDelegate(&d, -1, gfx::Rect()));
146  scoped_ptr<aura::Window> w11(
147      CreateTestWindowInShellWithDelegate(&d, -11, gfx::Rect()));
148  // |w111| will be owned and deleted by |w11|.
149  aura::Window* w111 =
150      CreateTestWindowInShellWithDelegate(&d, -111, gfx::Rect());
151  scoped_ptr<aura::Window> w2(
152      CreateTestWindowInShellWithDelegate(&d, -2, gfx::Rect()));
153
154  w1->AddTransientChild(w11.get());
155  w11->AddTransientChild(w111);
156
157  wm::ActivateWindow(w1.get());
158  EXPECT_TRUE(wm::IsActiveWindow(w1.get()));
159  wm::ActivateWindow(w2.get());
160  EXPECT_TRUE(wm::IsActiveWindow(w2.get()));
161
162  // Set up modality.
163  w11->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_WINDOW);
164  w111->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_WINDOW);
165
166  wm::ActivateWindow(w1.get());
167  EXPECT_TRUE(wm::IsActiveWindow(w111));
168
169  w111->Hide();
170  EXPECT_TRUE(wm::IsActiveWindow(w11.get()));
171
172  // TODO(oshima): Re-showing doesn't set the focus back to
173  // modal window. There is no such use case right now, but it
174  // probably should.
175
176  w11.reset();
177  EXPECT_TRUE(wm::IsActiveWindow(w1.get()));
178}
179
180// Modality also prevents events from being passed to the transient parent.
181TEST_F(WindowModalityControllerTest, Events) {
182  aura::test::TestWindowDelegate d;
183  scoped_ptr<aura::Window> w1(CreateTestWindowInShellWithDelegate(&d, -1,
184      gfx::Rect(0, 0, 100, 100)));
185  scoped_ptr<aura::Window> w11(CreateTestWindowInShellWithDelegate(&d, -11,
186      gfx::Rect(20, 20, 50, 50)));
187
188  w1->AddTransientChild(w11.get());
189
190  {
191    // Clicking a point within w1 should activate that window.
192    aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
193                                         gfx::Point(10, 10));
194    generator.ClickLeftButton();
195    EXPECT_TRUE(wm::IsActiveWindow(w1.get()));
196  }
197
198  w11->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_WINDOW);
199
200  {
201    // Clicking a point within w1 should activate w11.
202    aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
203                                         gfx::Point(10, 10));
204    generator.ClickLeftButton();
205    EXPECT_TRUE(wm::IsActiveWindow(w11.get()));
206  }
207}
208
209// Creates windows w1 and non activatiable child w11. Creates transient window
210// w2 and adds it as a transeint child of w1. Ensures that w2 is parented to
211// the parent of w1, and that GetModalTransient(w11) returns w2.
212TEST_F(WindowModalityControllerTest, GetModalTransient) {
213  aura::test::TestWindowDelegate d;
214  scoped_ptr<aura::Window> w1(
215      CreateTestWindowInShellWithDelegate(&d, -1, gfx::Rect()));
216  scoped_ptr<aura::Window> w11(
217      aura::test::CreateTestWindowWithDelegate(&d, -11, gfx::Rect(), w1.get()));
218  scoped_ptr<aura::Window> w2(
219      CreateTestWindowInShellWithDelegate(&d, -2, gfx::Rect()));
220  w2->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_WINDOW);
221
222  aura::Window* wt;
223  wt = views::corewm::GetModalTransient(w1.get());
224  ASSERT_EQ(static_cast<aura::Window*>(NULL), wt);
225
226  // Parent w2 to w1. It should get parented to the parent of w1.
227  w1->AddTransientChild(w2.get());
228  ASSERT_EQ(2U, w1->parent()->children().size());
229  EXPECT_EQ(-2, w1->parent()->children().at(1)->id());
230
231  // Request the modal transient window for w1, it should be w2.
232  wt = views::corewm::GetModalTransient(w1.get());
233  ASSERT_NE(static_cast<aura::Window*>(NULL), wt);
234  EXPECT_EQ(-2, wt->id());
235
236  // Request the modal transient window for w11, it should also be w2.
237  wt = views::corewm::GetModalTransient(w11.get());
238  ASSERT_NE(static_cast<aura::Window*>(NULL), wt);
239  EXPECT_EQ(-2, wt->id());
240}
241
242// Verifies we generate a capture lost when showing a modal window.
243TEST_F(WindowModalityControllerTest, ChangeCapture) {
244  views::Widget* widget = views::Widget::CreateWindowWithContext(
245      NULL, Shell::GetPrimaryRootWindow());
246  scoped_ptr<aura::Window> widget_window(widget->GetNativeView());
247  views::test::CaptureTrackingView* view = new views::test::CaptureTrackingView;
248  widget->client_view()->AddChildView(view);
249  widget->SetBounds(gfx::Rect(0, 0, 200, 200));
250  view->SetBoundsRect(widget->client_view()->GetLocalBounds());
251  widget->Show();
252
253  gfx::Point center(view->width() / 2, view->height() / 2);
254  views::View::ConvertPointToScreen(view, &center);
255  aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(), center);
256  generator.PressLeftButton();
257  EXPECT_TRUE(view->got_press());
258
259  views::Widget* modal_widget =
260      views::Widget::CreateWindowWithParent(NULL, widget->GetNativeView());
261  scoped_ptr<aura::Window> modal_window(modal_widget->GetNativeView());
262  modal_window->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_WINDOW);
263  views::test::CaptureTrackingView* modal_view =
264      new views::test::CaptureTrackingView;
265  modal_widget->client_view()->AddChildView(modal_view);
266  modal_widget->SetBounds(gfx::Rect(50, 50, 200, 200));
267  modal_view->SetBoundsRect(modal_widget->client_view()->GetLocalBounds());
268  modal_widget->Show();
269
270  EXPECT_TRUE(view->got_capture_lost());
271  generator.ReleaseLeftButton();
272
273  view->reset();
274
275  EXPECT_FALSE(modal_view->got_capture_lost());
276  EXPECT_FALSE(modal_view->got_press());
277
278  gfx::Point modal_center(modal_view->width() / 2, modal_view->height() / 2);
279  views::View::ConvertPointToScreen(modal_view, &modal_center);
280  generator.MoveMouseTo(modal_center, 1);
281  generator.PressLeftButton();
282  EXPECT_TRUE(modal_view->got_press());
283  EXPECT_FALSE(modal_view->got_capture_lost());
284  EXPECT_FALSE(view->got_capture_lost());
285  EXPECT_FALSE(view->got_press());
286}
287
288class TouchTrackerWindowDelegate : public aura::test::TestWindowDelegate {
289 public:
290  TouchTrackerWindowDelegate()
291      : received_touch_(false),
292        last_event_type_(ui::ET_UNKNOWN) {
293  }
294  virtual ~TouchTrackerWindowDelegate() {}
295
296  void reset() {
297    received_touch_ = false;
298    last_event_type_ = ui::ET_UNKNOWN;
299  }
300
301  bool received_touch() const { return received_touch_; }
302  ui::EventType last_event_type() const { return last_event_type_; }
303
304 private:
305  // Overridden from aura::test::TestWindowDelegate.
306  virtual void OnTouchEvent(ui::TouchEvent* event) OVERRIDE {
307    received_touch_ = true;
308    last_event_type_ = event->type();
309    aura::test::TestWindowDelegate::OnTouchEvent(event);
310  }
311
312  bool received_touch_;
313  ui::EventType last_event_type_;
314
315  DISALLOW_COPY_AND_ASSIGN(TouchTrackerWindowDelegate);
316};
317
318// Modality should prevent events from being passed to the transient parent.
319TEST_F(WindowModalityControllerTest, TouchEvent) {
320  TouchTrackerWindowDelegate d1;
321  scoped_ptr<aura::Window> w1(CreateTestWindowInShellWithDelegate(&d1,
322      -1, gfx::Rect(0, 0, 100, 100)));
323  TouchTrackerWindowDelegate d11;
324  scoped_ptr<aura::Window> w11(CreateTestWindowInShellWithDelegate(&d11,
325      -11, gfx::Rect(20, 20, 50, 50)));
326  aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
327                                       gfx::Point(10, 10));
328
329  w1->AddTransientChild(w11.get());
330  d1.reset();
331  d11.reset();
332
333  {
334    // Clicking a point within w1 should activate that window.
335    generator.PressMoveAndReleaseTouchTo(gfx::Point(10, 10));
336    EXPECT_TRUE(wm::IsActiveWindow(w1.get()));
337    EXPECT_TRUE(d1.received_touch());
338    EXPECT_FALSE(d11.received_touch());
339  }
340
341  {
342    // Adding a modal window while a touch is down should fire a touch cancel.
343    generator.PressTouch();
344    generator.MoveTouch(gfx::Point(10, 10));
345    d1.reset();
346    d11.reset();
347
348    w11->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_WINDOW);
349    EXPECT_TRUE(d1.received_touch());
350    EXPECT_EQ(ui::ET_TOUCH_CANCELLED, d1.last_event_type());
351    EXPECT_FALSE(d11.received_touch());
352  }
353}
354
355// Child-modal test.
356// Creates:
357// - A |parent| window that hosts a |modal_parent| window within itself. The
358//   |parent| and |modal_parent| windows are not the same window.  The
359//   |modal_parent| window is not activatable, because it's contained within the
360//   |parent| window.
361// - A |child| window with parent window |parent|, but is modal to
362//   |modal_parent| window.
363// Validates:
364// - Clicking on the |modal_parent| should activate the |child| window.
365// - Clicking on the |parent| window outside of the |modal_parent| bounds should
366//   activate the |parent| window.
367// - Clicking on the |child| while |parent| is active should activate the
368//   |child| window.
369// - Focus should follow the active window.
370TEST_F(WindowModalityControllerTest, ChildModal) {
371  views::test::ChildModalParent* delegate =
372      new views::test::ChildModalParent(CurrentContext());
373  views::Widget* widget = views::Widget::CreateWindowWithContextAndBounds(
374      delegate, CurrentContext(), gfx::Rect(0, 0, 400, 400));
375  widget->Show();
376
377  aura::Window* parent = widget->GetNativeView();
378  EXPECT_TRUE(wm::IsActiveWindow(parent));
379
380  aura::Window* modal_parent = delegate->GetModalParent();
381  EXPECT_NE(static_cast<aura::Window*>(NULL), modal_parent);
382  EXPECT_NE(parent, modal_parent);
383  EXPECT_FALSE(wm::IsActiveWindow(modal_parent));
384
385  delegate->ShowChild();
386  aura::Window* child = delegate->GetChild();
387  EXPECT_NE(static_cast<aura::Window*>(NULL), child);
388
389  EXPECT_TRUE(wm::IsActiveWindow(child));
390  EXPECT_FALSE(wm::IsActiveWindow(modal_parent));
391  EXPECT_FALSE(wm::IsActiveWindow(parent));
392
393  EXPECT_TRUE(child->HasFocus());
394  EXPECT_FALSE(modal_parent->HasFocus());
395  EXPECT_FALSE(parent->HasFocus());
396
397  wm::ActivateWindow(modal_parent);
398
399  EXPECT_TRUE(wm::IsActiveWindow(child));
400  EXPECT_FALSE(wm::IsActiveWindow(modal_parent));
401  EXPECT_FALSE(wm::IsActiveWindow(parent));
402
403  EXPECT_TRUE(child->HasFocus());
404  EXPECT_FALSE(modal_parent->HasFocus());
405  EXPECT_FALSE(parent->HasFocus());
406
407  wm::ActivateWindow(parent);
408
409  EXPECT_FALSE(wm::IsActiveWindow(child));
410  EXPECT_FALSE(wm::IsActiveWindow(modal_parent));
411  EXPECT_TRUE(wm::IsActiveWindow(parent));
412
413  EXPECT_FALSE(child->HasFocus());
414  EXPECT_FALSE(modal_parent->HasFocus());
415  EXPECT_TRUE(parent->HasFocus());
416
417  wm::ActivateWindow(child);
418
419  EXPECT_TRUE(wm::IsActiveWindow(child));
420  EXPECT_FALSE(wm::IsActiveWindow(modal_parent));
421  EXPECT_FALSE(wm::IsActiveWindow(parent));
422
423  EXPECT_TRUE(child->HasFocus());
424  EXPECT_FALSE(modal_parent->HasFocus());
425  EXPECT_FALSE(parent->HasFocus());
426}
427
428// Same as |ChildModal| test, but using |EventGenerator| rather than bypassing
429// it by calling |ActivateWindow|.
430TEST_F(WindowModalityControllerTest, ChildModalEventGenerator) {
431  views::test::ChildModalParent* delegate =
432      new views::test::ChildModalParent(CurrentContext());
433  views::Widget* widget = views::Widget::CreateWindowWithContextAndBounds(
434      delegate, CurrentContext(), gfx::Rect(0, 0, 400, 400));
435  widget->Show();
436
437  aura::Window* parent = widget->GetNativeView();
438  EXPECT_TRUE(wm::IsActiveWindow(parent));
439
440  aura::Window* modal_parent = delegate->GetModalParent();
441  EXPECT_NE(static_cast<aura::Window*>(NULL), modal_parent);
442  EXPECT_NE(parent, modal_parent);
443  EXPECT_FALSE(wm::IsActiveWindow(modal_parent));
444
445  delegate->ShowChild();
446  aura::Window* child = delegate->GetChild();
447  EXPECT_NE(static_cast<aura::Window*>(NULL), child);
448
449  EXPECT_TRUE(wm::IsActiveWindow(child));
450  EXPECT_FALSE(wm::IsActiveWindow(modal_parent));
451  EXPECT_FALSE(wm::IsActiveWindow(parent));
452
453  EXPECT_TRUE(child->HasFocus());
454  EXPECT_FALSE(modal_parent->HasFocus());
455  EXPECT_FALSE(parent->HasFocus());
456
457  {
458    aura::test::EventGenerator generator(
459        Shell::GetPrimaryRootWindow(),
460        parent->bounds().origin() +
461            gfx::Vector2d(10, parent->bounds().height() - 10));
462    generator.ClickLeftButton();
463    generator.ClickLeftButton();
464
465    EXPECT_TRUE(wm::IsActiveWindow(child));
466    EXPECT_FALSE(wm::IsActiveWindow(modal_parent));
467    EXPECT_FALSE(wm::IsActiveWindow(parent));
468
469    EXPECT_TRUE(child->HasFocus());
470    EXPECT_FALSE(modal_parent->HasFocus());
471    EXPECT_FALSE(parent->HasFocus());
472  }
473
474  {
475    aura::test::EventGenerator generator(
476        Shell::GetPrimaryRootWindow(),
477        parent->bounds().origin() + gfx::Vector2d(10, 10));
478    generator.ClickLeftButton();
479
480    EXPECT_FALSE(wm::IsActiveWindow(child));
481    EXPECT_FALSE(wm::IsActiveWindow(modal_parent));
482    EXPECT_TRUE(wm::IsActiveWindow(parent));
483
484    EXPECT_FALSE(child->HasFocus());
485    EXPECT_FALSE(modal_parent->HasFocus());
486    EXPECT_TRUE(parent->HasFocus());
487  }
488
489  {
490    aura::test::EventGenerator generator(
491        Shell::GetPrimaryRootWindow(),
492        child->bounds().origin() + gfx::Vector2d(10, 10));
493    generator.ClickLeftButton();
494
495    EXPECT_TRUE(wm::IsActiveWindow(child));
496    EXPECT_FALSE(wm::IsActiveWindow(modal_parent));
497    EXPECT_FALSE(wm::IsActiveWindow(parent));
498
499    EXPECT_TRUE(child->HasFocus());
500    EXPECT_FALSE(modal_parent->HasFocus());
501    EXPECT_FALSE(parent->HasFocus());
502  }
503}
504
505// Window-modal test for the case when the originally clicked window is an
506// ancestor of the modal parent.
507TEST_F(WindowModalityControllerTest, WindowModalAncestor) {
508  aura::test::TestWindowDelegate d;
509  scoped_ptr<aura::Window> w1(
510      CreateTestWindowInShellWithDelegate(&d, -1, gfx::Rect()));
511  scoped_ptr<aura::Window> w2(
512      aura::test::CreateTestWindowWithDelegate(&d, -11, gfx::Rect(), w1.get()));
513  scoped_ptr<aura::Window> w3(
514      aura::test::CreateTestWindowWithDelegate(&d, -11, gfx::Rect(), w2.get()));
515  scoped_ptr<aura::Window> w4(
516      CreateTestWindowInShellWithDelegate(&d, -2, gfx::Rect()));
517  w4->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_WINDOW);
518  w1->AddTransientChild(w4.get());
519
520  wm::ActivateWindow(w1.get());
521  EXPECT_TRUE(wm::IsActiveWindow(w4.get()));
522
523  wm::ActivateWindow(w2.get());
524  EXPECT_TRUE(wm::IsActiveWindow(w4.get()));
525
526  wm::ActivateWindow(w3.get());
527  EXPECT_TRUE(wm::IsActiveWindow(w4.get()));
528
529  wm::ActivateWindow(w4.get());
530  EXPECT_TRUE(wm::IsActiveWindow(w4.get()));
531}
532
533// Child-modal test for the case when the originally clicked window is an
534// ancestor of the modal parent.
535TEST_F(WindowModalityControllerTest, ChildModalAncestor) {
536  aura::test::TestWindowDelegate d;
537  scoped_ptr<aura::Window> w1(
538      CreateTestWindowInShellWithDelegate(&d, -1, gfx::Rect()));
539  scoped_ptr<aura::Window> w2(
540      aura::test::CreateTestWindowWithDelegate(&d, -11, gfx::Rect(), w1.get()));
541  scoped_ptr<aura::Window> w3(
542      aura::test::CreateTestWindowWithDelegate(&d, -11, gfx::Rect(), w2.get()));
543  scoped_ptr<aura::Window> w4(
544      CreateTestWindowInShellWithDelegate(&d, -2, gfx::Rect()));
545  w4->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_CHILD);
546  views::corewm::SetModalParent(w4.get(), w2.get());
547  w1->AddTransientChild(w4.get());
548
549  wm::ActivateWindow(w1.get());
550  EXPECT_TRUE(wm::IsActiveWindow(w1.get()));
551
552  wm::ActivateWindow(w2.get());
553  EXPECT_TRUE(wm::IsActiveWindow(w4.get()));
554
555  wm::ActivateWindow(w3.get());
556  EXPECT_TRUE(wm::IsActiveWindow(w4.get()));
557
558  wm::ActivateWindow(w4.get());
559  EXPECT_TRUE(wm::IsActiveWindow(w4.get()));
560}
561
562}  // namespace internal
563}  // namespace ash
564