OLD | NEW |
| (Empty) |
1 // Copyright 2014 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 "mojo/services/view_manager/public/cpp/view_manager.h" | |
6 | |
7 #include "base/auto_reset.h" | |
8 #include "base/bind.h" | |
9 #include "base/logging.h" | |
10 #include "mojo/public/cpp/application/application_connection.h" | |
11 #include "mojo/public/cpp/application/application_delegate.h" | |
12 #include "mojo/public/cpp/application/application_impl.h" | |
13 #include "mojo/public/cpp/application/service_provider_impl.h" | |
14 #include "mojo/public/interfaces/application/service_provider.mojom.h" | |
15 #include "mojo/services/geometry/public/cpp/geometry_util.h" | |
16 #include "mojo/services/view_manager/public/cpp/lib/view_manager_client_impl.h" | |
17 #include "mojo/services/view_manager/public/cpp/lib/view_private.h" | |
18 #include "mojo/services/view_manager/public/cpp/util.h" | |
19 #include "mojo/services/view_manager/public/cpp/view_manager_client_factory.h" | |
20 #include "mojo/services/view_manager/public/cpp/view_manager_delegate.h" | |
21 #include "mojo/services/view_manager/public/cpp/view_observer.h" | |
22 #include "shell/application_manager/application_manager.h" | |
23 #include "shell/shell_test_helper.h" | |
24 #include "testing/gtest/include/gtest/gtest.h" | |
25 | |
26 namespace mojo { | |
27 | |
28 namespace { | |
29 | |
30 const char kWindowManagerURL[] = "mojo:window_manager"; | |
31 const char kEmbeddedApp1URL[] = "mojo:embedded_app_1"; | |
32 | |
33 base::RunLoop* current_run_loop = NULL; | |
34 | |
35 void DoRunLoop() { | |
36 base::RunLoop run_loop; | |
37 current_run_loop = &run_loop; | |
38 current_run_loop->Run(); | |
39 current_run_loop = NULL; | |
40 } | |
41 | |
42 void QuitRunLoop() { | |
43 current_run_loop->Quit(); | |
44 } | |
45 | |
46 class ConnectApplicationLoader : public ApplicationLoader, | |
47 public ApplicationDelegate, | |
48 public ViewManagerDelegate { | |
49 public: | |
50 typedef base::Callback<void(View*)> LoadedCallback; | |
51 | |
52 explicit ConnectApplicationLoader(const LoadedCallback& callback) | |
53 : callback_(callback) {} | |
54 ~ConnectApplicationLoader() override {} | |
55 | |
56 private: | |
57 // Overridden from ApplicationDelegate: | |
58 void Initialize(ApplicationImpl* app) override { | |
59 view_manager_client_factory_.reset( | |
60 new ViewManagerClientFactory(app->shell(), this)); | |
61 } | |
62 | |
63 // Overridden from ApplicationLoader: | |
64 void Load(ApplicationManager* manager, | |
65 const GURL& url, | |
66 InterfaceRequest<Application> application_request, | |
67 LoadCallback callback) override { | |
68 ASSERT_TRUE(application_request.is_pending()); | |
69 scoped_ptr<ApplicationImpl> app( | |
70 new ApplicationImpl(this, application_request.Pass())); | |
71 apps_.push_back(app.release()); | |
72 } | |
73 | |
74 void OnApplicationError(ApplicationManager* manager, | |
75 const GURL& url) override {} | |
76 | |
77 bool ConfigureIncomingConnection(ApplicationConnection* connection) override { | |
78 connection->AddService(view_manager_client_factory_.get()); | |
79 return true; | |
80 } | |
81 | |
82 // Overridden from ViewManagerDelegate: | |
83 void OnEmbed(View* root, | |
84 InterfaceRequest<ServiceProvider> services, | |
85 ServiceProviderPtr exposed_services) override { | |
86 callback_.Run(root); | |
87 } | |
88 void OnViewManagerDisconnected(ViewManager* view_manager) override {} | |
89 | |
90 ScopedVector<ApplicationImpl> apps_; | |
91 LoadedCallback callback_; | |
92 scoped_ptr<ViewManagerClientFactory> view_manager_client_factory_; | |
93 | |
94 DISALLOW_COPY_AND_ASSIGN(ConnectApplicationLoader); | |
95 }; | |
96 | |
97 class BoundsChangeObserver : public ViewObserver { | |
98 public: | |
99 explicit BoundsChangeObserver(View* view) : view_(view) {} | |
100 ~BoundsChangeObserver() override {} | |
101 | |
102 private: | |
103 // Overridden from ViewObserver: | |
104 void OnViewBoundsChanged(View* view, | |
105 const Rect& old_bounds, | |
106 const Rect& new_bounds) override { | |
107 DCHECK_EQ(view, view_); | |
108 QuitRunLoop(); | |
109 } | |
110 | |
111 View* view_; | |
112 | |
113 DISALLOW_COPY_AND_ASSIGN(BoundsChangeObserver); | |
114 }; | |
115 | |
116 // Wait until the bounds of the supplied view change. | |
117 void WaitForBoundsToChange(View* view) { | |
118 BoundsChangeObserver observer(view); | |
119 view->AddObserver(&observer); | |
120 DoRunLoop(); | |
121 view->RemoveObserver(&observer); | |
122 } | |
123 | |
124 // Spins a runloop until the tree beginning at |root| has |tree_size| views | |
125 // (including |root|). | |
126 class TreeSizeMatchesObserver : public ViewObserver { | |
127 public: | |
128 TreeSizeMatchesObserver(View* tree, size_t tree_size) | |
129 : tree_(tree), | |
130 tree_size_(tree_size) {} | |
131 ~TreeSizeMatchesObserver() override {} | |
132 | |
133 bool IsTreeCorrectSize() { | |
134 return CountViews(tree_) == tree_size_; | |
135 } | |
136 | |
137 private: | |
138 // Overridden from ViewObserver: | |
139 void OnTreeChanged(const TreeChangeParams& params) override { | |
140 if (IsTreeCorrectSize()) | |
141 QuitRunLoop(); | |
142 } | |
143 | |
144 size_t CountViews(const View* view) const { | |
145 size_t count = 1; | |
146 View::Children::const_iterator it = view->children().begin(); | |
147 for (; it != view->children().end(); ++it) | |
148 count += CountViews(*it); | |
149 return count; | |
150 } | |
151 | |
152 View* tree_; | |
153 size_t tree_size_; | |
154 | |
155 DISALLOW_COPY_AND_ASSIGN(TreeSizeMatchesObserver); | |
156 }; | |
157 | |
158 void WaitForTreeSizeToMatch(View* view, size_t tree_size) { | |
159 TreeSizeMatchesObserver observer(view, tree_size); | |
160 if (observer.IsTreeCorrectSize()) | |
161 return; | |
162 view->AddObserver(&observer); | |
163 DoRunLoop(); | |
164 view->RemoveObserver(&observer); | |
165 } | |
166 | |
167 // Utility class that waits for the destruction of some number of views and | |
168 // views. | |
169 class DestructionObserver : public ViewObserver { | |
170 public: | |
171 // |views| or |views| can be NULL. | |
172 explicit DestructionObserver(std::set<Id>* views) : views_(views) {} | |
173 | |
174 private: | |
175 // Overridden from ViewObserver: | |
176 void OnViewDestroyed(View* view) override { | |
177 std::set<Id>::iterator it = views_->find(view->id()); | |
178 if (it != views_->end()) | |
179 views_->erase(it); | |
180 if (CanQuit()) | |
181 QuitRunLoop(); | |
182 } | |
183 | |
184 bool CanQuit() { | |
185 return !views_ || views_->empty(); | |
186 } | |
187 | |
188 std::set<Id>* views_; | |
189 | |
190 DISALLOW_COPY_AND_ASSIGN(DestructionObserver); | |
191 }; | |
192 | |
193 void WaitForDestruction(ViewManager* view_manager, std::set<Id>* views) { | |
194 DestructionObserver observer(views); | |
195 DCHECK(views); | |
196 if (views) { | |
197 for (std::set<Id>::const_iterator it = views->begin(); | |
198 it != views->end(); ++it) { | |
199 view_manager->GetViewById(*it)->AddObserver(&observer); | |
200 } | |
201 } | |
202 DoRunLoop(); | |
203 } | |
204 | |
205 class OrderChangeObserver : public ViewObserver { | |
206 public: | |
207 OrderChangeObserver(View* view) : view_(view) { | |
208 view_->AddObserver(this); | |
209 } | |
210 ~OrderChangeObserver() override { view_->RemoveObserver(this); } | |
211 | |
212 private: | |
213 // Overridden from ViewObserver: | |
214 void OnViewReordered(View* view, | |
215 View* relative_view, | |
216 OrderDirection direction) override { | |
217 DCHECK_EQ(view, view_); | |
218 QuitRunLoop(); | |
219 } | |
220 | |
221 View* view_; | |
222 | |
223 DISALLOW_COPY_AND_ASSIGN(OrderChangeObserver); | |
224 }; | |
225 | |
226 void WaitForOrderChange(ViewManager* view_manager, View* view) { | |
227 OrderChangeObserver observer(view); | |
228 DoRunLoop(); | |
229 } | |
230 | |
231 // Tracks a view's destruction. Query is_valid() for current state. | |
232 class ViewTracker : public ViewObserver { | |
233 public: | |
234 explicit ViewTracker(View* view) : view_(view) { | |
235 view_->AddObserver(this); | |
236 } | |
237 ~ViewTracker() override { | |
238 if (view_) | |
239 view_->RemoveObserver(this); | |
240 } | |
241 | |
242 bool is_valid() const { return !!view_; } | |
243 | |
244 private: | |
245 // Overridden from ViewObserver: | |
246 void OnViewDestroyed(View* view) override { | |
247 DCHECK_EQ(view, view_); | |
248 view_ = NULL; | |
249 } | |
250 | |
251 int id_; | |
252 View* view_; | |
253 | |
254 DISALLOW_COPY_AND_ASSIGN(ViewTracker); | |
255 }; | |
256 | |
257 } // namespace | |
258 | |
259 // ViewManager ----------------------------------------------------------------- | |
260 | |
261 // These tests model synchronization of two peer connections to the view manager | |
262 // service, that are given access to some root view. | |
263 | |
264 class ViewManagerTest : public testing::Test { | |
265 public: | |
266 ViewManagerTest() | |
267 : connect_loop_(NULL), | |
268 loaded_view_manager_(NULL), | |
269 window_manager_(NULL), | |
270 commit_count_(0) {} | |
271 | |
272 protected: | |
273 ViewManager* window_manager() { return window_manager_; } | |
274 | |
275 View* CreateViewInParent(View* parent) { | |
276 ViewManager* parent_manager = parent->view_manager(); | |
277 View* view = parent_manager->CreateView(); | |
278 view->SetVisible(true); | |
279 parent->AddChild(view); | |
280 return view; | |
281 } | |
282 | |
283 // Embeds another version of the test app @ view. | |
284 ViewManager* Embed(ViewManager* view_manager, View* view) { | |
285 DCHECK_EQ(view_manager, view->view_manager()); | |
286 view->Embed(kEmbeddedApp1URL); | |
287 RunRunLoop(); | |
288 return GetLoadedViewManager(); | |
289 } | |
290 | |
291 ViewManager* GetLoadedViewManager() { | |
292 ViewManager* view_manager = loaded_view_manager_; | |
293 loaded_view_manager_ = NULL; | |
294 return view_manager; | |
295 } | |
296 | |
297 void UnloadApplication(const GURL& url) { | |
298 test_helper_.SetLoaderForURL(scoped_ptr<ApplicationLoader>(), url); | |
299 } | |
300 | |
301 private: | |
302 // Overridden from testing::Test: | |
303 void SetUp() override { | |
304 ConnectApplicationLoader::LoadedCallback ready_callback = base::Bind( | |
305 &ViewManagerTest::OnViewManagerLoaded, base::Unretained(this)); | |
306 test_helper_.Init(); | |
307 test_helper_.SetLoaderForURL( | |
308 scoped_ptr<ApplicationLoader>( | |
309 new ConnectApplicationLoader(ready_callback)), | |
310 GURL(kWindowManagerURL)); | |
311 test_helper_.SetLoaderForURL( | |
312 scoped_ptr<ApplicationLoader>( | |
313 new ConnectApplicationLoader(ready_callback)), | |
314 GURL(kEmbeddedApp1URL)); | |
315 | |
316 // TODO(sky): resolve this. Need to establish initial connection. | |
317 } | |
318 | |
319 void OnViewManagerLoaded(View* root) { | |
320 loaded_view_manager_ = root->view_manager(); | |
321 connect_loop_->Quit(); | |
322 } | |
323 | |
324 void RunRunLoop() { | |
325 base::RunLoop run_loop; | |
326 connect_loop_ = &run_loop; | |
327 connect_loop_->Run(); | |
328 connect_loop_ = NULL; | |
329 } | |
330 | |
331 base::RunLoop* connect_loop_; | |
332 shell::ShellTestHelper test_helper_; | |
333 // Used to receive the most recent view manager loaded by an embed action. | |
334 ViewManager* loaded_view_manager_; | |
335 // The View Manager connection held by the window manager (app running at the | |
336 // root view). | |
337 ViewManager* window_manager_; | |
338 int commit_count_; | |
339 | |
340 DISALLOW_COPY_AND_ASSIGN(ViewManagerTest); | |
341 }; | |
342 | |
343 // TODO(sky): all of these tests are disabled as each test triggers running | |
344 // ViewsInit, which tries to register the same set of paths with the | |
345 // PathService, triggering a DCHECK. | |
346 TEST_F(ViewManagerTest, DISABLED_SetUp) {} | |
347 | |
348 TEST_F(ViewManagerTest, DISABLED_Embed) { | |
349 View* view = window_manager()->CreateView(); | |
350 view->SetVisible(true); | |
351 window_manager()->GetRoot()->AddChild(view); | |
352 ViewManager* embedded = Embed(window_manager(), view); | |
353 EXPECT_TRUE(NULL != embedded); | |
354 | |
355 View* view_in_embedded = embedded->GetRoot(); | |
356 EXPECT_EQ(view->parent(), window_manager()->GetRoot()); | |
357 EXPECT_EQ(NULL, view_in_embedded->parent()); | |
358 } | |
359 | |
360 // Window manager has two views, N1 and N11. Embeds A at N1. A should not see | |
361 // N11. | |
362 // TODO(sky): Update client lib to match server. | |
363 TEST_F(ViewManagerTest, DISABLED_EmbeddedDoesntSeeChild) { | |
364 View* view = window_manager()->CreateView(); | |
365 view->SetVisible(true); | |
366 window_manager()->GetRoot()->AddChild(view); | |
367 View* nested = window_manager()->CreateView(); | |
368 nested->SetVisible(true); | |
369 view->AddChild(nested); | |
370 | |
371 ViewManager* embedded = Embed(window_manager(), view); | |
372 EXPECT_EQ(embedded->GetRoot()->children().front()->id(), | |
373 nested->id()); | |
374 EXPECT_TRUE(embedded->GetRoot()->children().empty()); | |
375 EXPECT_TRUE(nested->parent() == NULL); | |
376 } | |
377 | |
378 // http://crbug.com/396300 | |
379 TEST_F(ViewManagerTest, DISABLED_ViewManagerDestroyed_CleanupView) { | |
380 View* view = window_manager()->CreateView(); | |
381 view->SetVisible(true); | |
382 window_manager()->GetRoot()->AddChild(view); | |
383 ViewManager* embedded = Embed(window_manager(), view); | |
384 | |
385 Id view_id = view->id(); | |
386 | |
387 UnloadApplication(GURL(kWindowManagerURL)); | |
388 | |
389 std::set<Id> views; | |
390 views.insert(view_id); | |
391 WaitForDestruction(embedded, &views); | |
392 | |
393 EXPECT_EQ(nullptr, embedded->GetRoot()); | |
394 } | |
395 | |
396 // TODO(beng): write a replacement test for the one that once existed here: | |
397 // This test validates the following scenario: | |
398 // - a view originating from one connection | |
399 // - a view originating from a second connection | |
400 // + the connection originating the view is destroyed | |
401 // -> the view should still exist (since the second connection is live) but | |
402 // should be disconnected from any views. | |
403 // http://crbug.com/396300 | |
404 // | |
405 // TODO(beng): The new test should validate the scenario as described above | |
406 // except that the second connection still has a valid tree. | |
407 | |
408 // Verifies that bounds changes applied to a view hierarchy in one connection | |
409 // are reflected to another. | |
410 TEST_F(ViewManagerTest, DISABLED_SetBounds) { | |
411 View* view = window_manager()->CreateView(); | |
412 view->SetVisible(true); | |
413 window_manager()->GetRoot()->AddChild(view); | |
414 ViewManager* embedded = Embed(window_manager(), view); | |
415 | |
416 View* view_in_embedded = embedded->GetViewById(view->id()); | |
417 EXPECT_EQ(view->bounds(), view_in_embedded->bounds()); | |
418 | |
419 Rect rect; | |
420 rect.width = rect.height = 100; | |
421 view->SetBounds(rect); | |
422 EXPECT_NE(view->bounds(), view_in_embedded->bounds()); | |
423 WaitForBoundsToChange(view_in_embedded); | |
424 EXPECT_EQ(view->bounds(), view_in_embedded->bounds()); | |
425 } | |
426 | |
427 // Verifies that bounds changes applied to a view owned by a different | |
428 // connection are refused. | |
429 TEST_F(ViewManagerTest, DISABLED_SetBoundsSecurity) { | |
430 View* view = window_manager()->CreateView(); | |
431 view->SetVisible(true); | |
432 window_manager()->GetRoot()->AddChild(view); | |
433 ViewManager* embedded = Embed(window_manager(), view); | |
434 | |
435 View* view_in_embedded = embedded->GetViewById(view->id()); | |
436 Rect rect; | |
437 rect.width = 800; | |
438 rect.height = 600; | |
439 view->SetBounds(rect); | |
440 WaitForBoundsToChange(view_in_embedded); | |
441 | |
442 rect.width = 1024; | |
443 rect.height = 768; | |
444 view_in_embedded->SetBounds(rect); | |
445 // Bounds change should have been rejected. | |
446 EXPECT_EQ(view->bounds(), view_in_embedded->bounds()); | |
447 } | |
448 | |
449 // Verifies that a view can only be destroyed by the connection that created it. | |
450 TEST_F(ViewManagerTest, DISABLED_DestroySecurity) { | |
451 View* view = window_manager()->CreateView(); | |
452 view->SetVisible(true); | |
453 window_manager()->GetRoot()->AddChild(view); | |
454 ViewManager* embedded = Embed(window_manager(), view); | |
455 | |
456 View* view_in_embedded = embedded->GetViewById(view->id()); | |
457 | |
458 ViewTracker tracker2(view_in_embedded); | |
459 view_in_embedded->Destroy(); | |
460 // View should not have been destroyed. | |
461 EXPECT_TRUE(tracker2.is_valid()); | |
462 | |
463 ViewTracker tracker1(view); | |
464 view->Destroy(); | |
465 EXPECT_FALSE(tracker1.is_valid()); | |
466 } | |
467 | |
468 TEST_F(ViewManagerTest, DISABLED_MultiRoots) { | |
469 View* view1 = window_manager()->CreateView(); | |
470 view1->SetVisible(true); | |
471 window_manager()->GetRoot()->AddChild(view1); | |
472 View* view2 = window_manager()->CreateView(); | |
473 view2->SetVisible(true); | |
474 window_manager()->GetRoot()->AddChild(view2); | |
475 ViewManager* embedded1 = Embed(window_manager(), view1); | |
476 ViewManager* embedded2 = Embed(window_manager(), view2); | |
477 EXPECT_EQ(embedded1, embedded2); | |
478 } | |
479 | |
480 TEST_F(ViewManagerTest, DISABLED_EmbeddingIdentity) { | |
481 View* view = window_manager()->CreateView(); | |
482 view->SetVisible(true); | |
483 window_manager()->GetRoot()->AddChild(view); | |
484 ViewManager* embedded = Embed(window_manager(), view); | |
485 EXPECT_EQ(kWindowManagerURL, embedded->GetEmbedderURL()); | |
486 } | |
487 | |
488 TEST_F(ViewManagerTest, DISABLED_Reorder) { | |
489 View* view1 = window_manager()->CreateView(); | |
490 view1->SetVisible(true); | |
491 window_manager()->GetRoot()->AddChild(view1); | |
492 | |
493 ViewManager* embedded = Embed(window_manager(), view1); | |
494 | |
495 View* view11 = embedded->CreateView(); | |
496 view11->SetVisible(true); | |
497 embedded->GetRoot()->AddChild(view11); | |
498 View* view12 = embedded->CreateView(); | |
499 view12->SetVisible(true); | |
500 embedded->GetRoot()->AddChild(view12); | |
501 | |
502 View* view1_in_wm = window_manager()->GetViewById(view1->id()); | |
503 | |
504 { | |
505 WaitForTreeSizeToMatch(view1, 2u); | |
506 view11->MoveToFront(); | |
507 WaitForOrderChange(window_manager(), | |
508 window_manager()->GetViewById(view11->id())); | |
509 | |
510 EXPECT_EQ(view1_in_wm->children().front(), | |
511 window_manager()->GetViewById(view12->id())); | |
512 EXPECT_EQ(view1_in_wm->children().back(), | |
513 window_manager()->GetViewById(view11->id())); | |
514 } | |
515 | |
516 { | |
517 view11->MoveToBack(); | |
518 WaitForOrderChange(window_manager(), | |
519 window_manager()->GetViewById(view11->id())); | |
520 | |
521 EXPECT_EQ(view1_in_wm->children().front(), | |
522 window_manager()->GetViewById(view11->id())); | |
523 EXPECT_EQ(view1_in_wm->children().back(), | |
524 window_manager()->GetViewById(view12->id())); | |
525 } | |
526 } | |
527 | |
528 namespace { | |
529 | |
530 class VisibilityChangeObserver : public ViewObserver { | |
531 public: | |
532 explicit VisibilityChangeObserver(View* view) : view_(view) { | |
533 view_->AddObserver(this); | |
534 } | |
535 ~VisibilityChangeObserver() override { view_->RemoveObserver(this); } | |
536 | |
537 private: | |
538 // Overridden from ViewObserver: | |
539 void OnViewVisibilityChanged(View* view) override { | |
540 EXPECT_EQ(view, view_); | |
541 QuitRunLoop(); | |
542 } | |
543 | |
544 View* view_; | |
545 | |
546 DISALLOW_COPY_AND_ASSIGN(VisibilityChangeObserver); | |
547 }; | |
548 | |
549 } // namespace | |
550 | |
551 TEST_F(ViewManagerTest, DISABLED_Visible) { | |
552 View* view1 = window_manager()->CreateView(); | |
553 view1->SetVisible(true); | |
554 window_manager()->GetRoot()->AddChild(view1); | |
555 | |
556 // Embed another app and verify initial state. | |
557 ViewManager* embedded = Embed(window_manager(), view1); | |
558 ASSERT_NE(nullptr, embedded->GetRoot()); | |
559 View* embedded_root = embedded->GetRoot(); | |
560 EXPECT_TRUE(embedded_root->visible()); | |
561 EXPECT_TRUE(embedded_root->IsDrawn()); | |
562 | |
563 // Change the visible state from the first connection and verify its mirrored | |
564 // correctly to the embedded app. | |
565 { | |
566 VisibilityChangeObserver observer(embedded_root); | |
567 view1->SetVisible(false); | |
568 DoRunLoop(); | |
569 } | |
570 | |
571 EXPECT_FALSE(view1->visible()); | |
572 EXPECT_FALSE(view1->IsDrawn()); | |
573 | |
574 EXPECT_FALSE(embedded_root->visible()); | |
575 EXPECT_FALSE(embedded_root->IsDrawn()); | |
576 | |
577 // Make the node visible again. | |
578 { | |
579 VisibilityChangeObserver observer(embedded_root); | |
580 view1->SetVisible(true); | |
581 DoRunLoop(); | |
582 } | |
583 | |
584 EXPECT_TRUE(view1->visible()); | |
585 EXPECT_TRUE(view1->IsDrawn()); | |
586 | |
587 EXPECT_TRUE(embedded_root->visible()); | |
588 EXPECT_TRUE(embedded_root->IsDrawn()); | |
589 } | |
590 | |
591 namespace { | |
592 | |
593 class DrawnChangeObserver : public ViewObserver { | |
594 public: | |
595 explicit DrawnChangeObserver(View* view) : view_(view) { | |
596 view_->AddObserver(this); | |
597 } | |
598 ~DrawnChangeObserver() override { view_->RemoveObserver(this); } | |
599 | |
600 private: | |
601 // Overridden from ViewObserver: | |
602 void OnViewDrawnChanged(View* view) override { | |
603 EXPECT_EQ(view, view_); | |
604 QuitRunLoop(); | |
605 } | |
606 | |
607 View* view_; | |
608 | |
609 DISALLOW_COPY_AND_ASSIGN(DrawnChangeObserver); | |
610 }; | |
611 | |
612 } // namespace | |
613 | |
614 TEST_F(ViewManagerTest, DISABLED_Drawn) { | |
615 View* view1 = window_manager()->CreateView(); | |
616 view1->SetVisible(true); | |
617 window_manager()->GetRoot()->AddChild(view1); | |
618 | |
619 // Embed another app and verify initial state. | |
620 ViewManager* embedded = Embed(window_manager(), view1); | |
621 ASSERT_NE(nullptr, embedded->GetRoot()); | |
622 View* embedded_root = embedded->GetRoot(); | |
623 EXPECT_TRUE(embedded_root->visible()); | |
624 EXPECT_TRUE(embedded_root->IsDrawn()); | |
625 | |
626 // Change the visibility of the root, this should propagate a drawn state | |
627 // change to |embedded|. | |
628 { | |
629 DrawnChangeObserver observer(embedded_root); | |
630 window_manager()->GetRoot()->SetVisible(false); | |
631 DoRunLoop(); | |
632 } | |
633 | |
634 EXPECT_TRUE(view1->visible()); | |
635 EXPECT_FALSE(view1->IsDrawn()); | |
636 | |
637 EXPECT_TRUE(embedded_root->visible()); | |
638 EXPECT_FALSE(embedded_root->IsDrawn()); | |
639 } | |
640 | |
641 // TODO(beng): tests for view event dispatcher. | |
642 // - verify that we see events for all views. | |
643 | |
644 // TODO(beng): tests for focus: | |
645 // - focus between two views known to a connection | |
646 // - focus between views unknown to one of the connections. | |
647 // - focus between views unknown to either connection. | |
648 | |
649 // TODO(sky): need test of root being destroyed with existing views. See | |
650 // 434555 for specific case. | |
651 | |
652 } // namespace mojo | |
OLD | NEW |