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 <string> | |
6 #include <vector> | |
7 | |
8 #include "base/message_loop/message_loop.h" | |
9 #include "mojo/converters/geometry/geometry_type_converters.h" | |
10 #include "mojo/public/interfaces/application/service_provider.mojom.h" | |
11 #include "mojo/services/view_manager/cpp/types.h" | |
12 #include "mojo/services/view_manager/cpp/util.h" | |
13 #include "mojo/services/view_manager/interfaces/view_manager.mojom.h" | |
14 #include "mojo/services/window_manager/interfaces/window_manager.mojom.h" | |
15 #include "mojo/services/window_manager/interfaces/window_manager_internal.mojom.
h" | |
16 #include "services/view_manager/client_connection.h" | |
17 #include "services/view_manager/connection_manager.h" | |
18 #include "services/view_manager/connection_manager_delegate.h" | |
19 #include "services/view_manager/display_manager.h" | |
20 #include "services/view_manager/ids.h" | |
21 #include "services/view_manager/server_view.h" | |
22 #include "services/view_manager/test_change_tracker.h" | |
23 #include "services/view_manager/view_manager_service_impl.h" | |
24 #include "testing/gtest/include/gtest/gtest.h" | |
25 #include "ui/gfx/geometry/rect.h" | |
26 | |
27 using mojo::Array; | |
28 using mojo::ErrorCode; | |
29 using mojo::InterfaceRequest; | |
30 using mojo::ServiceProvider; | |
31 using mojo::ServiceProviderPtr; | |
32 using mojo::String; | |
33 using mojo::ViewDataPtr; | |
34 | |
35 namespace view_manager { | |
36 namespace { | |
37 | |
38 // ----------------------------------------------------------------------------- | |
39 | |
40 // ViewManagerClient implementation that logs all calls to a TestChangeTracker. | |
41 // TODO(sky): refactor so both this and ViewManagerServiceAppTest share code. | |
42 class TestViewManagerClient : public mojo::ViewManagerClient { | |
43 public: | |
44 TestViewManagerClient() {} | |
45 ~TestViewManagerClient() override {} | |
46 | |
47 TestChangeTracker* tracker() { return &tracker_; } | |
48 | |
49 private: | |
50 // ViewManagerClient: | |
51 void OnEmbed(uint16_t connection_id, | |
52 const String& embedder_url, | |
53 ViewDataPtr root, | |
54 mojo::ViewManagerServicePtr view_manager_service, | |
55 InterfaceRequest<ServiceProvider> services, | |
56 ServiceProviderPtr exposed_services, | |
57 mojo::ScopedMessagePipeHandle window_manager_pipe) override { | |
58 tracker_.OnEmbed(connection_id, embedder_url, root.Pass()); | |
59 } | |
60 void OnEmbeddedAppDisconnected(uint32_t view) override { | |
61 tracker_.OnEmbeddedAppDisconnected(view); | |
62 } | |
63 void OnViewBoundsChanged(uint32_t view, | |
64 mojo::RectPtr old_bounds, | |
65 mojo::RectPtr new_bounds) override { | |
66 tracker_.OnViewBoundsChanged(view, old_bounds.Pass(), new_bounds.Pass()); | |
67 } | |
68 void OnViewViewportMetricsChanged( | |
69 mojo::ViewportMetricsPtr old_metrics, | |
70 mojo::ViewportMetricsPtr new_metrics) override { | |
71 tracker_.OnViewViewportMetricsChanged(old_metrics.Pass(), | |
72 new_metrics.Pass()); | |
73 } | |
74 void OnViewHierarchyChanged(uint32_t view, | |
75 uint32_t new_parent, | |
76 uint32_t old_parent, | |
77 Array<ViewDataPtr> views) override { | |
78 tracker_.OnViewHierarchyChanged(view, new_parent, old_parent, views.Pass()); | |
79 } | |
80 void OnViewReordered(uint32_t view_id, | |
81 uint32_t relative_view_id, | |
82 mojo::OrderDirection direction) override { | |
83 tracker_.OnViewReordered(view_id, relative_view_id, direction); | |
84 } | |
85 void OnViewDeleted(uint32_t view) override { tracker_.OnViewDeleted(view); } | |
86 void OnViewVisibilityChanged(uint32_t view, bool visible) override { | |
87 tracker_.OnViewVisibilityChanged(view, visible); | |
88 } | |
89 void OnViewDrawnStateChanged(uint32_t view, bool drawn) override { | |
90 tracker_.OnViewDrawnStateChanged(view, drawn); | |
91 } | |
92 void OnViewSharedPropertyChanged(uint32_t view, | |
93 const String& name, | |
94 Array<uint8_t> new_data) override { | |
95 tracker_.OnViewSharedPropertyChanged(view, name, new_data.Pass()); | |
96 } | |
97 void OnViewInputEvent(uint32_t view, | |
98 mojo::EventPtr event, | |
99 const mojo::Callback<void()>& callback) override { | |
100 tracker_.OnViewInputEvent(view, event.Pass()); | |
101 } | |
102 void OnPerformAction(uint32_t view_id, | |
103 const String& name, | |
104 const mojo::Callback<void(bool)>& callback) override {} | |
105 | |
106 TestChangeTracker tracker_; | |
107 | |
108 DISALLOW_COPY_AND_ASSIGN(TestViewManagerClient); | |
109 }; | |
110 | |
111 // ----------------------------------------------------------------------------- | |
112 | |
113 // ClientConnection implementation that vends TestViewManagerClient. | |
114 class TestClientConnection : public ClientConnection { | |
115 public: | |
116 explicit TestClientConnection(scoped_ptr<ViewManagerServiceImpl> service_impl) | |
117 : ClientConnection(service_impl.Pass(), &client_) {} | |
118 ~TestClientConnection() override {} | |
119 | |
120 TestViewManagerClient* client() { return &client_; } | |
121 | |
122 private: | |
123 TestViewManagerClient client_; | |
124 | |
125 DISALLOW_COPY_AND_ASSIGN(TestClientConnection); | |
126 }; | |
127 | |
128 // ----------------------------------------------------------------------------- | |
129 | |
130 // Empty implementation of ConnectionManagerDelegate. | |
131 class TestConnectionManagerDelegate : public ConnectionManagerDelegate { | |
132 public: | |
133 TestConnectionManagerDelegate() : last_connection_(nullptr) {} | |
134 ~TestConnectionManagerDelegate() override {} | |
135 | |
136 TestViewManagerClient* last_client() { | |
137 return last_connection_ ? last_connection_->client() : nullptr; | |
138 } | |
139 | |
140 TestClientConnection* last_connection() { return last_connection_; } | |
141 | |
142 private: | |
143 // ConnectionManagerDelegate: | |
144 void OnLostConnectionToWindowManager() override {} | |
145 | |
146 ClientConnection* CreateClientConnectionForEmbedAtView( | |
147 ConnectionManager* connection_manager, | |
148 mojo::InterfaceRequest<mojo::ViewManagerService> service_request, | |
149 mojo::ConnectionSpecificId creator_id, | |
150 const std::string& creator_url, | |
151 const std::string& url, | |
152 const ViewId& root_id) override { | |
153 scoped_ptr<ViewManagerServiceImpl> service(new ViewManagerServiceImpl( | |
154 connection_manager, creator_id, creator_url, url, root_id)); | |
155 last_connection_ = new TestClientConnection(service.Pass()); | |
156 return last_connection_; | |
157 } | |
158 ClientConnection* CreateClientConnectionForEmbedAtView( | |
159 ConnectionManager* connection_manager, | |
160 mojo::InterfaceRequest<mojo::ViewManagerService> service_request, | |
161 mojo::ConnectionSpecificId creator_id, | |
162 const std::string& creator_url, | |
163 const ViewId& root_id, | |
164 mojo::ViewManagerClientPtr client) override { | |
165 NOTIMPLEMENTED(); | |
166 return nullptr; | |
167 } | |
168 | |
169 TestClientConnection* last_connection_; | |
170 | |
171 DISALLOW_COPY_AND_ASSIGN(TestConnectionManagerDelegate); | |
172 }; | |
173 | |
174 // ----------------------------------------------------------------------------- | |
175 | |
176 // Empty implementation of DisplayManager. | |
177 class TestDisplayManager : public DisplayManager { | |
178 public: | |
179 TestDisplayManager() {} | |
180 ~TestDisplayManager() override {} | |
181 | |
182 // DisplayManager: | |
183 void Init(ConnectionManager* connection_manager) override {} | |
184 void SchedulePaint(const ServerView* view, const gfx::Rect& bounds) override { | |
185 } | |
186 void SetViewportSize(const gfx::Size& size) override {} | |
187 const mojo::ViewportMetrics& GetViewportMetrics() override { | |
188 return display_metrices_; | |
189 } | |
190 | |
191 private: | |
192 mojo::ViewportMetrics display_metrices_; | |
193 | |
194 DISALLOW_COPY_AND_ASSIGN(TestDisplayManager); | |
195 }; | |
196 | |
197 // ----------------------------------------------------------------------------- | |
198 | |
199 // Empty implementation of WindowManagerInternal. | |
200 class TestWindowManagerInternal : public mojo::WindowManagerInternal { | |
201 public: | |
202 TestWindowManagerInternal() {} | |
203 ~TestWindowManagerInternal() override {} | |
204 | |
205 // WindowManagerInternal: | |
206 void CreateWindowManagerForViewManagerClient( | |
207 uint16_t connection_id, | |
208 mojo::ScopedMessagePipeHandle window_manager_pipe) override {} | |
209 void SetViewManagerClient(mojo::ScopedMessagePipeHandle) override {} | |
210 | |
211 private: | |
212 DISALLOW_COPY_AND_ASSIGN(TestWindowManagerInternal); | |
213 }; | |
214 | |
215 } // namespace | |
216 | |
217 // ----------------------------------------------------------------------------- | |
218 | |
219 class ViewManagerServiceTest : public testing::Test { | |
220 public: | |
221 ViewManagerServiceTest() : wm_client_(nullptr) {} | |
222 ~ViewManagerServiceTest() override {} | |
223 | |
224 // ViewManagerServiceImpl for the window manager. | |
225 ViewManagerServiceImpl* wm_connection() { | |
226 return connection_manager_->GetConnection(1); | |
227 } | |
228 | |
229 TestViewManagerClient* last_view_manager_client() { | |
230 return delegate_.last_client(); | |
231 } | |
232 | |
233 TestClientConnection* last_client_connection() { | |
234 return delegate_.last_connection(); | |
235 } | |
236 | |
237 ConnectionManager* connection_manager() { return connection_manager_.get(); } | |
238 | |
239 TestViewManagerClient* wm_client() { return wm_client_; } | |
240 | |
241 protected: | |
242 // testing::Test: | |
243 void SetUp() override { | |
244 connection_manager_.reset(new ConnectionManager( | |
245 &delegate_, scoped_ptr<DisplayManager>(new TestDisplayManager), | |
246 &wm_internal_)); | |
247 scoped_ptr<ViewManagerServiceImpl> service(new ViewManagerServiceImpl( | |
248 connection_manager_.get(), kInvalidConnectionId, std::string(), | |
249 std::string("mojo:window_manager"), RootViewId())); | |
250 scoped_ptr<TestClientConnection> client_connection( | |
251 new TestClientConnection(service.Pass())); | |
252 wm_client_ = client_connection->client(); | |
253 ASSERT_TRUE(wm_client_ != nullptr); | |
254 connection_manager_->SetWindowManagerClientConnection( | |
255 client_connection.Pass()); | |
256 ASSERT_TRUE(wm_connection() != nullptr); | |
257 ASSERT_TRUE(wm_connection()->root() != nullptr); | |
258 } | |
259 | |
260 private: | |
261 // TestViewManagerClient that is used for the WM connection. | |
262 TestViewManagerClient* wm_client_; | |
263 | |
264 TestWindowManagerInternal wm_internal_; | |
265 TestConnectionManagerDelegate delegate_; | |
266 scoped_ptr<ConnectionManager> connection_manager_; | |
267 base::MessageLoop message_loop_; | |
268 | |
269 DISALLOW_COPY_AND_ASSIGN(ViewManagerServiceTest); | |
270 }; | |
271 | |
272 namespace { | |
273 | |
274 const ServerView* GetFirstCloned(const ServerView* view) { | |
275 for (const ServerView* child : view->GetChildren()) { | |
276 if (child->id() == ClonedViewId()) | |
277 return child; | |
278 } | |
279 return nullptr; | |
280 } | |
281 | |
282 // Provides common setup for animation tests. Creates the following views: | |
283 // 0,1 (the root, provided by view manager) | |
284 // 1,1 the second connection is embedded here (view owned by wm_connection()). | |
285 // 2,1 bounds=1,2 11x22 | |
286 // 2,2 bounds=2,3 6x7 | |
287 // 2,3 bounds=3,4 6x7 | |
288 // CloneAndAnimate() is invoked for 2,2. | |
289 void SetUpAnimate1(ViewManagerServiceTest* test, ViewId* embed_view_id) { | |
290 *embed_view_id = ViewId(test->wm_connection()->id(), 1); | |
291 EXPECT_EQ(ErrorCode::NONE, test->wm_connection()->CreateView(*embed_view_id)); | |
292 EXPECT_TRUE(test->wm_connection()->SetViewVisibility(*embed_view_id, true)); | |
293 EXPECT_TRUE(test->wm_connection()->AddView(*(test->wm_connection()->root()), | |
294 *embed_view_id)); | |
295 test->wm_connection()->EmbedUrl(std::string(), *embed_view_id, nullptr, | |
296 nullptr); | |
297 ViewManagerServiceImpl* connection1 = | |
298 test->connection_manager()->GetConnectionWithRoot(*embed_view_id); | |
299 ASSERT_TRUE(connection1 != nullptr); | |
300 ASSERT_NE(connection1, test->wm_connection()); | |
301 | |
302 const ViewId child1(connection1->id(), 1); | |
303 EXPECT_EQ(ErrorCode::NONE, connection1->CreateView(child1)); | |
304 const ViewId child2(connection1->id(), 2); | |
305 EXPECT_EQ(ErrorCode::NONE, connection1->CreateView(child2)); | |
306 const ViewId child3(connection1->id(), 3); | |
307 EXPECT_EQ(ErrorCode::NONE, connection1->CreateView(child3)); | |
308 | |
309 ServerView* v1 = connection1->GetView(child1); | |
310 v1->SetVisible(true); | |
311 v1->SetBounds(gfx::Rect(1, 2, 11, 22)); | |
312 ServerView* v2 = connection1->GetView(child2); | |
313 v2->SetVisible(true); | |
314 v2->SetBounds(gfx::Rect(2, 3, 6, 7)); | |
315 ServerView* v3 = connection1->GetView(child3); | |
316 v3->SetVisible(true); | |
317 v3->SetBounds(gfx::Rect(3, 4, 6, 7)); | |
318 | |
319 EXPECT_TRUE(connection1->AddView(*embed_view_id, child1)); | |
320 EXPECT_TRUE(connection1->AddView(child1, child2)); | |
321 EXPECT_TRUE(connection1->AddView(child2, child3)); | |
322 | |
323 TestViewManagerClient* connection1_client = test->last_view_manager_client(); | |
324 connection1_client->tracker()->changes()->clear(); | |
325 test->wm_client()->tracker()->changes()->clear(); | |
326 EXPECT_TRUE(test->connection_manager()->CloneAndAnimate(child2)); | |
327 EXPECT_TRUE(connection1_client->tracker()->changes()->empty()); | |
328 EXPECT_TRUE(test->wm_client()->tracker()->changes()->empty()); | |
329 | |
330 // We cloned v2. The cloned view ends up as a sibling of it. | |
331 const ServerView* cloned_view = GetFirstCloned(connection1->GetView(child1)); | |
332 ASSERT_TRUE(cloned_view); | |
333 // |cloned_view| should have one and only one cloned child (corresponds to | |
334 // |child3|). | |
335 ASSERT_EQ(1u, cloned_view->GetChildren().size()); | |
336 EXPECT_TRUE(cloned_view->GetChildren()[0]->id() == ClonedViewId()); | |
337 | |
338 // Cloned views should match the bounds of the view they were cloned from. | |
339 EXPECT_EQ(v2->bounds(), cloned_view->bounds()); | |
340 EXPECT_EQ(v3->bounds(), cloned_view->GetChildren()[0]->bounds()); | |
341 | |
342 // Cloned views are owned by the ConnectionManager and shouldn't be returned | |
343 // from ViewManagerServiceImpl::GetView. | |
344 EXPECT_TRUE(connection1->GetView(ClonedViewId()) == nullptr); | |
345 EXPECT_TRUE(test->wm_connection()->GetView(ClonedViewId()) == nullptr); | |
346 } | |
347 | |
348 } // namespace | |
349 | |
350 // Verifies ViewManagerService::GetViewTree() doesn't return cloned views. | |
351 TEST_F(ViewManagerServiceTest, ConnectionsCantSeeClonedViews) { | |
352 ViewId embed_view_id; | |
353 EXPECT_NO_FATAL_FAILURE(SetUpAnimate1(this, &embed_view_id)); | |
354 | |
355 ViewManagerServiceImpl* connection1 = | |
356 connection_manager()->GetConnectionWithRoot(embed_view_id); | |
357 | |
358 const ViewId child1(connection1->id(), 1); | |
359 const ViewId child2(connection1->id(), 2); | |
360 const ViewId child3(connection1->id(), 3); | |
361 | |
362 // Verify the root doesn't see any cloned views. | |
363 std::vector<const ServerView*> views( | |
364 wm_connection()->GetViewTree(*wm_connection()->root())); | |
365 ASSERT_EQ(5u, views.size()); | |
366 ASSERT_TRUE(views[0]->id() == *wm_connection()->root()); | |
367 ASSERT_TRUE(views[1]->id() == embed_view_id); | |
368 ASSERT_TRUE(views[2]->id() == child1); | |
369 ASSERT_TRUE(views[3]->id() == child2); | |
370 ASSERT_TRUE(views[4]->id() == child3); | |
371 | |
372 // Verify connection1 doesn't see any cloned views. | |
373 std::vector<const ServerView*> v1_views( | |
374 connection1->GetViewTree(embed_view_id)); | |
375 ASSERT_EQ(4u, v1_views.size()); | |
376 ASSERT_TRUE(v1_views[0]->id() == embed_view_id); | |
377 ASSERT_TRUE(v1_views[1]->id() == child1); | |
378 ASSERT_TRUE(v1_views[2]->id() == child2); | |
379 ASSERT_TRUE(v1_views[3]->id() == child3); | |
380 } | |
381 | |
382 TEST_F(ViewManagerServiceTest, ClonedViewsPromotedOnConnectionClose) { | |
383 ViewId embed_view_id; | |
384 EXPECT_NO_FATAL_FAILURE(SetUpAnimate1(this, &embed_view_id)); | |
385 | |
386 // Destroy connection1, which should force the cloned view to become a child | |
387 // of where it was embedded (the embedded view still exists). | |
388 connection_manager()->OnConnectionError(last_client_connection()); | |
389 | |
390 ServerView* embed_view = wm_connection()->GetView(embed_view_id); | |
391 ASSERT_TRUE(embed_view != nullptr); | |
392 const ServerView* cloned_view = GetFirstCloned(embed_view); | |
393 ASSERT_TRUE(cloned_view); | |
394 ASSERT_EQ(1u, cloned_view->GetChildren().size()); | |
395 EXPECT_TRUE(cloned_view->GetChildren()[0]->id() == ClonedViewId()); | |
396 | |
397 // Because the cloned view changed parents its bounds should have changed. | |
398 EXPECT_EQ(gfx::Rect(3, 5, 6, 7), cloned_view->bounds()); | |
399 // The bounds of the cloned child should not have changed though. | |
400 EXPECT_EQ(gfx::Rect(3, 4, 6, 7), cloned_view->GetChildren()[0]->bounds()); | |
401 } | |
402 | |
403 TEST_F(ViewManagerServiceTest, ClonedViewsPromotedOnHide) { | |
404 ViewId embed_view_id; | |
405 EXPECT_NO_FATAL_FAILURE(SetUpAnimate1(this, &embed_view_id)); | |
406 | |
407 ViewManagerServiceImpl* connection1 = | |
408 connection_manager()->GetConnectionWithRoot(embed_view_id); | |
409 | |
410 // Hide the parent of the cloned view, which should force the cloned view to | |
411 // become a sibling of the parent. | |
412 const ServerView* view_to_hide = | |
413 connection1->GetView(ViewId(connection1->id(), 1)); | |
414 ASSERT_TRUE(connection1->SetViewVisibility(view_to_hide->id(), false)); | |
415 | |
416 const ServerView* cloned_view = GetFirstCloned(view_to_hide->parent()); | |
417 ASSERT_TRUE(cloned_view); | |
418 ASSERT_EQ(1u, cloned_view->GetChildren().size()); | |
419 EXPECT_TRUE(cloned_view->GetChildren()[0]->id() == ClonedViewId()); | |
420 EXPECT_EQ(2u, cloned_view->parent()->GetChildren().size()); | |
421 EXPECT_TRUE(cloned_view->parent()->GetChildren()[1] == cloned_view); | |
422 } | |
423 | |
424 // Clone and animate on a tree with more depth. Basically that of | |
425 // SetUpAnimate1() but cloning 2,1. | |
426 TEST_F(ViewManagerServiceTest, CloneAndAnimateLargerDepth) { | |
427 const ViewId embed_view_id(wm_connection()->id(), 1); | |
428 EXPECT_EQ(ErrorCode::NONE, wm_connection()->CreateView(embed_view_id)); | |
429 EXPECT_TRUE(wm_connection()->SetViewVisibility(embed_view_id, true)); | |
430 EXPECT_TRUE( | |
431 wm_connection()->AddView(*(wm_connection()->root()), embed_view_id)); | |
432 wm_connection()->EmbedUrl(std::string(), embed_view_id, nullptr, nullptr); | |
433 ViewManagerServiceImpl* connection1 = | |
434 connection_manager()->GetConnectionWithRoot(embed_view_id); | |
435 ASSERT_TRUE(connection1 != nullptr); | |
436 ASSERT_NE(connection1, wm_connection()); | |
437 | |
438 const ViewId child1(connection1->id(), 1); | |
439 EXPECT_EQ(ErrorCode::NONE, connection1->CreateView(child1)); | |
440 const ViewId child2(connection1->id(), 2); | |
441 EXPECT_EQ(ErrorCode::NONE, connection1->CreateView(child2)); | |
442 const ViewId child3(connection1->id(), 3); | |
443 EXPECT_EQ(ErrorCode::NONE, connection1->CreateView(child3)); | |
444 | |
445 ServerView* v1 = connection1->GetView(child1); | |
446 v1->SetVisible(true); | |
447 connection1->GetView(child2)->SetVisible(true); | |
448 connection1->GetView(child3)->SetVisible(true); | |
449 | |
450 EXPECT_TRUE(connection1->AddView(embed_view_id, child1)); | |
451 EXPECT_TRUE(connection1->AddView(child1, child2)); | |
452 EXPECT_TRUE(connection1->AddView(child2, child3)); | |
453 | |
454 TestViewManagerClient* connection1_client = last_view_manager_client(); | |
455 connection1_client->tracker()->changes()->clear(); | |
456 wm_client()->tracker()->changes()->clear(); | |
457 EXPECT_TRUE(connection_manager()->CloneAndAnimate(child1)); | |
458 EXPECT_TRUE(connection1_client->tracker()->changes()->empty()); | |
459 EXPECT_TRUE(wm_client()->tracker()->changes()->empty()); | |
460 | |
461 // We cloned v1. The cloned view ends up as a sibling of it. | |
462 const ServerView* cloned_view = GetFirstCloned(v1->parent()); | |
463 ASSERT_TRUE(cloned_view); | |
464 // |cloned_view| should have a child and its child should have a child. | |
465 ASSERT_EQ(1u, cloned_view->GetChildren().size()); | |
466 const ServerView* cloned_view_child = cloned_view->GetChildren()[0]; | |
467 EXPECT_EQ(1u, cloned_view_child->GetChildren().size()); | |
468 EXPECT_TRUE(cloned_view_child->id() == ClonedViewId()); | |
469 } | |
470 | |
471 } // namespace view_manager | |
OLD | NEW |