| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "mojo/services/public/cpp/view_manager/view_manager.h" | 5 #include "mojo/services/public/cpp/view_manager/view_manager.h" |
| 6 | 6 |
| 7 #include "base/auto_reset.h" | 7 #include "base/auto_reset.h" |
| 8 #include "base/bind.h" | 8 #include "base/bind.h" |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "mojo/public/cpp/application/application.h" | 10 #include "mojo/public/cpp/application/application.h" |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 43 QuitRunLoop(); | 43 QuitRunLoop(); |
| 44 } | 44 } |
| 45 | 45 |
| 46 void WaitForAllChangesToBeAcked(ViewManager* manager) { | 46 void WaitForAllChangesToBeAcked(ViewManager* manager) { |
| 47 ViewManagerPrivate(manager).synchronizer()->set_changes_acked_callback( | 47 ViewManagerPrivate(manager).synchronizer()->set_changes_acked_callback( |
| 48 base::Bind(&QuitRunLoopOnChangesAcked)); | 48 base::Bind(&QuitRunLoopOnChangesAcked)); |
| 49 DoRunLoop(); | 49 DoRunLoop(); |
| 50 ViewManagerPrivate(manager).synchronizer()->ClearChangesAckedCallback(); | 50 ViewManagerPrivate(manager).synchronizer()->ClearChangesAckedCallback(); |
| 51 } | 51 } |
| 52 | 52 |
| 53 // Used with IViewManager::Connect(). Creates a TestViewManagerClientConnection, | |
| 54 // which creates and owns the ViewManagerProxy. | |
| 55 class ConnectServiceLoader : public ServiceLoader { | 53 class ConnectServiceLoader : public ServiceLoader { |
| 56 public: | 54 public: |
| 57 explicit ConnectServiceLoader(base::Callback<void(ViewManager*)> callback) | 55 explicit ConnectServiceLoader(base::Callback<void(ViewManager*)> callback) |
| 58 : callback_(callback) {} | 56 : callback_(callback) {} |
| 59 virtual ~ConnectServiceLoader() {} | 57 virtual ~ConnectServiceLoader() {} |
| 60 | 58 |
| 61 // ServiceLoader: | 59 private: |
| 60 // Overridden from ServiceLoader: |
| 62 virtual void LoadService(ServiceManager* manager, | 61 virtual void LoadService(ServiceManager* manager, |
| 63 const GURL& url, | 62 const GURL& url, |
| 64 ScopedMessagePipeHandle shell_handle) OVERRIDE { | 63 ScopedMessagePipeHandle shell_handle) OVERRIDE { |
| 65 scoped_ptr<Application> app(new Application(shell_handle.Pass())); | 64 scoped_ptr<Application> app(new Application(shell_handle.Pass())); |
| 66 ViewManager::Create(app.get(), callback_); | 65 ViewManager::Create(app.get(), callback_); |
| 67 apps_.push_back(app.release()); | 66 apps_.push_back(app.release()); |
| 68 } | 67 } |
| 69 virtual void OnServiceError(ServiceManager* manager, | 68 virtual void OnServiceError(ServiceManager* manager, |
| 70 const GURL& url) OVERRIDE { | 69 const GURL& url) OVERRIDE { |
| 71 } | 70 } |
| 72 | 71 |
| 73 private: | |
| 74 ScopedVector<Application> apps_; | 72 ScopedVector<Application> apps_; |
| 75 base::Callback<void(ViewManager*)> callback_; | 73 base::Callback<void(ViewManager*)> callback_; |
| 76 | 74 |
| 77 DISALLOW_COPY_AND_ASSIGN(ConnectServiceLoader); | 75 DISALLOW_COPY_AND_ASSIGN(ConnectServiceLoader); |
| 78 }; | 76 }; |
| 79 | 77 |
| 80 class ActiveViewChangedObserver : public ViewTreeNodeObserver { | 78 class ActiveViewChangedObserver : public ViewTreeNodeObserver { |
| 81 public: | 79 public: |
| 82 explicit ActiveViewChangedObserver(ViewTreeNode* node) | 80 explicit ActiveViewChangedObserver(ViewTreeNode* node) |
| 83 : node_(node) {} | 81 : node_(node) {} |
| (...skipping 231 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 315 void DestroyViewManager1() {} | 313 void DestroyViewManager1() {} |
| 316 ViewManager* view_manager_1() { return NULL; } | 314 ViewManager* view_manager_1() { return NULL; } |
| 317 ViewManager* view_manager_2() { return NULL; } | 315 ViewManager* view_manager_2() { return NULL; } |
| 318 | 316 |
| 319 ViewManager* GetLoadedViewManager() { | 317 ViewManager* GetLoadedViewManager() { |
| 320 ViewManager* view_manager = loaded_view_manager_; | 318 ViewManager* view_manager = loaded_view_manager_; |
| 321 loaded_view_manager_ = NULL; | 319 loaded_view_manager_ = NULL; |
| 322 return view_manager; | 320 return view_manager; |
| 323 } | 321 } |
| 324 | 322 |
| 323 void UnloadApplication(const GURL& url) { |
| 324 test_helper_.SetLoaderForURL(scoped_ptr<ServiceLoader>(), url); |
| 325 } |
| 326 |
| 325 private: | 327 private: |
| 326 // Overridden from testing::Test: | 328 // Overridden from testing::Test: |
| 327 virtual void SetUp() OVERRIDE { | 329 virtual void SetUp() OVERRIDE { |
| 328 test_helper_.Init(); | 330 test_helper_.Init(); |
| 329 test_helper_.SetLoaderForURL( | 331 test_helper_.SetLoaderForURL( |
| 330 scoped_ptr<ServiceLoader>(new ConnectServiceLoader( | 332 scoped_ptr<ServiceLoader>(new ConnectServiceLoader( |
| 331 base::Bind(&ViewManagerTest::OnViewManagerLoaded, | 333 base::Bind(&ViewManagerTest::OnViewManagerLoaded, |
| 332 base::Unretained(this)))), | 334 base::Unretained(this)))), |
| 333 GURL(kTestServiceURL)); | 335 GURL(kTestServiceURL)); |
| 334 test_helper_.SetLoaderForURL( | 336 test_helper_.SetLoaderForURL( |
| (...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 469 nested->Destroy(); | 471 nested->Destroy(); |
| 470 | 472 |
| 471 std::set<TransportNodeId> nodes; | 473 std::set<TransportNodeId> nodes; |
| 472 nodes.insert(id); | 474 nodes.insert(id); |
| 473 WaitForDestruction(embedded, &nodes, NULL); | 475 WaitForDestruction(embedded, &nodes, NULL); |
| 474 | 476 |
| 475 EXPECT_TRUE(embedded->tree()->children().empty()); | 477 EXPECT_TRUE(embedded->tree()->children().empty()); |
| 476 EXPECT_EQ(NULL, embedded->GetNodeById(id)); | 478 EXPECT_EQ(NULL, embedded->GetNodeById(id)); |
| 477 } | 479 } |
| 478 | 480 |
| 479 // TODO(beng): provide a way to terminate an application. | 481 TEST_F(ViewManagerTest, ViewManagerDestroyed_CleanupNode) { |
| 480 TEST_F(ViewManagerTest, DISABLED_ViewManagerDestroyed_CleanupNode) { | 482 ViewTreeNode* node = ViewTreeNode::Create(window_manager()); |
| 481 ViewTreeNode* node1 = CreateNodeInParent(view_manager_1()->tree()); | 483 window_manager()->tree()->AddChild(node); |
| 482 WaitForTreeSizeToMatch(view_manager_2()->tree(), 2); | 484 ViewManager* embedded = Embed(window_manager(), node); |
| 483 | 485 |
| 484 TransportNodeId id = node1->id(); | 486 TransportNodeId node_id = node->id(); |
| 485 DestroyViewManager1(); | 487 |
| 488 UnloadApplication(GURL(kTestServiceURL)); |
| 489 |
| 486 std::set<TransportNodeId> nodes; | 490 std::set<TransportNodeId> nodes; |
| 487 nodes.insert(id); | 491 nodes.insert(node_id); |
| 488 WaitForDestruction(view_manager_2(), &nodes, NULL); | 492 WaitForDestruction(embedded, &nodes, NULL); |
| 489 | 493 |
| 490 // tree() should still be valid, since it's owned by neither connection. | 494 EXPECT_EQ(NULL, embedded->tree()); |
| 491 EXPECT_TRUE(view_manager_2()->tree()->children().empty()); | |
| 492 } | 495 } |
| 493 | 496 |
| 494 TEST_F(ViewManagerTest, SetActiveView) { | 497 TEST_F(ViewManagerTest, SetActiveView) { |
| 495 ViewTreeNode* node = ViewTreeNode::Create(window_manager()); | 498 ViewTreeNode* node = ViewTreeNode::Create(window_manager()); |
| 496 window_manager()->tree()->AddChild(node); | 499 window_manager()->tree()->AddChild(node); |
| 497 ViewManager* embedded = Embed(window_manager(), node); | 500 ViewManager* embedded = Embed(window_manager(), node); |
| 498 | 501 |
| 499 View* view = View::Create(window_manager()); | 502 View* view = View::Create(window_manager()); |
| 500 node->SetActiveView(view); | 503 node->SetActiveView(view); |
| 501 | 504 |
| (...skipping 21 matching lines...) Expand all Loading... |
| 523 | 526 |
| 524 std::set<TransportViewId> views; | 527 std::set<TransportViewId> views; |
| 525 views.insert(view_id); | 528 views.insert(view_id); |
| 526 WaitForDestruction(embedded, NULL, &views); | 529 WaitForDestruction(embedded, NULL, &views); |
| 527 EXPECT_EQ(NULL, node_in_embedded->active_view()); | 530 EXPECT_EQ(NULL, node_in_embedded->active_view()); |
| 528 EXPECT_EQ(NULL, embedded->GetViewById(view_id)); | 531 EXPECT_EQ(NULL, embedded->GetViewById(view_id)); |
| 529 } | 532 } |
| 530 | 533 |
| 531 // Destroying the connection that created a node and view should result in that | 534 // Destroying the connection that created a node and view should result in that |
| 532 // node and view disappearing from all connections that see them. | 535 // node and view disappearing from all connections that see them. |
| 533 TEST_F(ViewManagerTest, DISABLED_ViewManagerDestroyed_CleanupNodeAndView) { | 536 TEST_F(ViewManagerTest, ViewManagerDestroyed_CleanupNodeAndView) { |
| 534 ViewTreeNode* node1 = CreateNodeInParent(view_manager_1()->tree()); | 537 ViewTreeNode* node = ViewTreeNode::Create(window_manager()); |
| 535 WaitForTreeSizeToMatch(view_manager_2()->tree(), 2); | 538 window_manager()->tree()->AddChild(node); |
| 539 View* view = View::Create(window_manager()); |
| 540 node->SetActiveView(view); |
| 541 ViewManager* embedded = Embed(window_manager(), node); |
| 536 | 542 |
| 537 View* view1 = View::Create(view_manager_1()); | 543 TransportNodeId node_id = node->id(); |
| 538 node1->SetActiveView(view1); | 544 TransportViewId view_id = view->id(); |
| 539 | 545 |
| 540 ViewTreeNode* node1_2 = view_manager_2()->tree()->GetChildById(node1->id()); | 546 UnloadApplication(GURL(kTestServiceURL)); |
| 541 WaitForActiveViewToChange(node1_2); | |
| 542 | 547 |
| 543 TransportNodeId node1_id = node1->id(); | 548 std::set<TransportNodeId> observed_nodes; |
| 544 TransportViewId view1_id = view1->id(); | 549 observed_nodes.insert(node_id); |
| 550 std::set<TransportViewId> observed_views; |
| 551 observed_views.insert(view_id); |
| 552 WaitForDestruction(embedded, &observed_nodes, &observed_views); |
| 545 | 553 |
| 546 DestroyViewManager1(); | 554 EXPECT_EQ(NULL, embedded->tree()); |
| 547 std::set<TransportNodeId> observed_nodes; | 555 EXPECT_EQ(NULL, embedded->GetNodeById(node_id)); |
| 548 observed_nodes.insert(node1_id); | 556 EXPECT_EQ(NULL, embedded->GetViewById(view_id)); |
| 549 std::set<TransportViewId> observed_views; | |
| 550 observed_views.insert(view1_id); | |
| 551 WaitForDestruction(view_manager_2(), &observed_nodes, &observed_views); | |
| 552 | |
| 553 // tree() should still be valid, since it's owned by neither connection. | |
| 554 EXPECT_TRUE(view_manager_2()->tree()->children().empty()); | |
| 555 EXPECT_EQ(NULL, view_manager_2()->GetNodeById(node1_id)); | |
| 556 EXPECT_EQ(NULL, view_manager_2()->GetViewById(view1_id)); | |
| 557 } | 557 } |
| 558 | 558 |
| 559 // This test validates the following scenario: | 559 // This test validates the following scenario: |
| 560 // - a node originating from one connection | 560 // - a node originating from one connection |
| 561 // - a view originating from a second connection | 561 // - a view originating from a second connection |
| 562 // + the connection originating the node is destroyed | 562 // + the connection originating the node is destroyed |
| 563 // -> the view should still exist (since the second connection is live) but | 563 // -> the view should still exist (since the second connection is live) but |
| 564 // should be disconnected from any nodes. | 564 // should be disconnected from any nodes. |
| 565 TEST_F(ViewManagerTest, | 565 TEST_F(ViewManagerTest, |
| 566 DISABLED_ViewManagerDestroyed_CleanupNodeAndViewFromDifferentConnections) { | 566 ViewManagerDestroyed_CleanupNodeAndViewFromDifferentConnections) { |
| 567 ViewTreeNode* node1 = CreateNodeInParent(view_manager_1()->tree()); | 567 ViewTreeNode* node = ViewTreeNode::Create(window_manager()); |
| 568 WaitForTreeSizeToMatch(view_manager_2()->tree(), 2); | 568 window_manager()->tree()->AddChild(node); |
| 569 ViewManager* embedded = Embed(window_manager(), node); |
| 570 View* view_in_embedded = View::Create(embedded); |
| 571 ViewTreeNode* node_in_embedded = embedded->GetNodeById(node->id()); |
| 572 node_in_embedded->SetActiveView(view_in_embedded); |
| 569 | 573 |
| 570 View* view1_2 = View::Create(view_manager_2()); | 574 WaitForActiveViewToChange(node); |
| 571 ViewTreeNode* node1_2 = view_manager_2()->tree()->GetChildById(node1->id()); | |
| 572 node1_2->SetActiveView(view1_2); | |
| 573 WaitForActiveViewToChange(node1); | |
| 574 | 575 |
| 575 TransportNodeId node1_id = node1->id(); | 576 TransportNodeId node_id = node->id(); |
| 576 TransportViewId view1_2_id = view1_2->id(); | 577 TransportViewId view_id = view_in_embedded->id(); |
| 577 | 578 |
| 578 DestroyViewManager1(); | 579 UnloadApplication(GURL(kTestServiceURL)); |
| 579 std::set<TransportNodeId> nodes; | 580 std::set<TransportNodeId> nodes; |
| 580 nodes.insert(node1_id); | 581 nodes.insert(node_id); |
| 581 WaitForDestruction(view_manager_2(), &nodes, NULL); | 582 WaitForDestruction(embedded, &nodes, NULL); |
| 582 | 583 |
| 583 // tree() should still be valid, since it's owned by neither connection. | 584 EXPECT_EQ(NULL, embedded->tree()); |
| 584 EXPECT_TRUE(view_manager_2()->tree()->children().empty()); | 585 // node was owned by the window manager, so it should be gone. |
| 585 // node1 was owned by the first connection, so it should be gone. | 586 EXPECT_EQ(NULL, embedded->GetNodeById(node_id)); |
| 586 EXPECT_EQ(NULL, view_manager_2()->GetNodeById(node1_id)); | 587 // view_in_embedded was owned by the embedded app, so it should still exist, |
| 587 // view1_2 was owned by the second connection, so it should still exist, but | 588 // but disconnected from the node tree. |
| 588 // disconnected from the node tree. | 589 EXPECT_EQ(view_in_embedded, embedded->GetViewById(view_id)); |
| 589 View* another_view1_2 = view_manager_2()->GetViewById(view1_2_id); | 590 EXPECT_EQ(NULL, view_in_embedded->node()); |
| 590 EXPECT_EQ(view1_2, another_view1_2); | |
| 591 EXPECT_EQ(NULL, view1_2->node()); | |
| 592 } | 591 } |
| 593 | 592 |
| 594 // This test verifies that it is not possible to set the active view to a view | 593 // This test verifies that it is not possible to set the active view to a view |
| 595 // defined in a different connection. | 594 // defined in a different connection. |
| 596 // TODO(beng): write these tests for ViewTreeNode::AddChild(), RemoveChild() and | 595 // TODO(beng): write these tests for ViewTreeNode::AddChild(), RemoveChild() and |
| 597 // Contains(). | 596 // Contains(). |
| 598 TEST_F(ViewManagerTest, SetActiveViewAcrossConnection) { | 597 TEST_F(ViewManagerTest, SetActiveViewAcrossConnection) { |
| 599 ViewTreeNode* node = ViewTreeNode::Create(window_manager()); | 598 ViewTreeNode* node = ViewTreeNode::Create(window_manager()); |
| 600 window_manager()->tree()->AddChild(node); | 599 window_manager()->tree()->AddChild(node); |
| 601 ViewManager* embedded = Embed(window_manager(), node); | 600 ViewManager* embedded = Embed(window_manager(), node); |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 679 // Node should not have been destroyed. | 678 // Node should not have been destroyed. |
| 680 EXPECT_TRUE(tracker2.is_valid()); | 679 EXPECT_TRUE(tracker2.is_valid()); |
| 681 | 680 |
| 682 NodeTracker tracker1(node); | 681 NodeTracker tracker1(node); |
| 683 node->Destroy(); | 682 node->Destroy(); |
| 684 EXPECT_FALSE(tracker1.is_valid()); | 683 EXPECT_FALSE(tracker1.is_valid()); |
| 685 } | 684 } |
| 686 | 685 |
| 687 } // namespace view_manager | 686 } // namespace view_manager |
| 688 } // namespace mojo | 687 } // namespace mojo |
| OLD | NEW |