Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(178)

Side by Side Diff: mojo/services/window_manager/focus_controller_unittest.cc

Issue 765753003: Move window_manager service implementation to //services (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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 "mojo/services/window_manager/focus_controller.h"
6
7 #include "mojo/converters/geometry/geometry_type_converters.h"
8 #include "mojo/services/window_manager/basic_focus_rules.h"
9 #include "mojo/services/window_manager/focus_controller_observer.h"
10 #include "mojo/services/window_manager/view_event_dispatcher.h"
11 #include "mojo/services/window_manager/view_targeter.h"
12 #include "mojo/services/window_manager/window_manager_test_util.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14 #include "ui/events/test/event_generator.h"
15 #include "ui/gfx/geometry/rect.h"
16
17 namespace mojo {
18
19 // Counts the number of events that occur.
20 class FocusNotificationObserver : public FocusControllerObserver {
21 public:
22 FocusNotificationObserver()
23 : activation_changed_count_(0),
24 focus_changed_count_(0),
25 reactivation_count_(0),
26 reactivation_requested_window_(NULL),
27 reactivation_actual_window_(NULL) {}
28 ~FocusNotificationObserver() override {}
29
30 void ExpectCounts(int activation_changed_count, int focus_changed_count) {
31 EXPECT_EQ(activation_changed_count, activation_changed_count_);
32 EXPECT_EQ(focus_changed_count, focus_changed_count_);
33 }
34 int reactivation_count() const { return reactivation_count_; }
35 View* reactivation_requested_window() const {
36 return reactivation_requested_window_;
37 }
38 View* reactivation_actual_window() const {
39 return reactivation_actual_window_;
40 }
41
42 protected:
43 // Overridden from FocusControllerObserver:
44 void OnViewActivated(View* gained_active, View* lost_active) override {
45 ++activation_changed_count_;
46 }
47
48 void OnViewFocused(View* gained_focus, View* lost_focus) override {
49 ++focus_changed_count_;
50 }
51
52 void OnAttemptToReactivateView(View* request_active,
53 View* actual_active) override {
54 ++reactivation_count_;
55 reactivation_requested_window_ = request_active;
56 reactivation_actual_window_ = actual_active;
57 }
58
59 private:
60 int activation_changed_count_;
61 int focus_changed_count_;
62 int reactivation_count_;
63 View* reactivation_requested_window_;
64 View* reactivation_actual_window_;
65
66 DISALLOW_COPY_AND_ASSIGN(FocusNotificationObserver);
67 };
68
69 class ScopedFocusNotificationObserver : public FocusNotificationObserver {
70 public:
71 ScopedFocusNotificationObserver(FocusController* focus_controller)
72 : focus_controller_(focus_controller) {
73 focus_controller_->AddObserver(this);
74 }
75 ~ScopedFocusNotificationObserver() override {
76 focus_controller_->RemoveObserver(this);
77 }
78
79 private:
80 mojo::FocusController* focus_controller_;
81
82 DISALLOW_COPY_AND_ASSIGN(ScopedFocusNotificationObserver);
83 };
84
85 // Only responds to events if a message contains |target| as a parameter.
86 class ScopedFilteringFocusNotificationObserver
87 : public FocusNotificationObserver {
88 public:
89 ScopedFilteringFocusNotificationObserver(FocusController* focus_controller,
90 View* target)
91 : focus_controller_(focus_controller), target_(target) {
92 focus_controller_->AddObserver(this);
93 }
94 ~ScopedFilteringFocusNotificationObserver() override {
95 focus_controller_->RemoveObserver(this);
96 }
97
98 private:
99 // Overridden from FocusControllerObserver:
100 void OnViewActivated(View* gained_active, View* lost_active) override {
101 if (gained_active == target_ || lost_active == target_)
102 FocusNotificationObserver::OnViewActivated(gained_active, lost_active);
103 }
104
105 void OnViewFocused(View* gained_focus, View* lost_focus) override {
106 if (gained_focus == target_ || lost_focus == target_)
107 FocusNotificationObserver::OnViewFocused(gained_focus, lost_focus);
108 }
109
110 void OnAttemptToReactivateView(View* request_active,
111 View* actual_active) override {
112 if (request_active == target_ || actual_active == target_) {
113 FocusNotificationObserver::OnAttemptToReactivateView(request_active,
114 actual_active);
115 }
116 }
117
118 mojo::FocusController* focus_controller_;
119 View* target_;
120
121 DISALLOW_COPY_AND_ASSIGN(ScopedFilteringFocusNotificationObserver);
122 };
123
124 // Used to fake the handling of events in the pre-target phase.
125 class SimpleEventHandler : public ui::EventHandler {
126 public:
127 SimpleEventHandler() {}
128 ~SimpleEventHandler() override {}
129
130 // Overridden from ui::EventHandler:
131 void OnMouseEvent(ui::MouseEvent* event) override {
132 event->SetHandled();
133 }
134 void OnGestureEvent(ui::GestureEvent* event) override {
135 event->SetHandled();
136 }
137
138 private:
139 DISALLOW_COPY_AND_ASSIGN(SimpleEventHandler);
140 };
141
142 // BasicFocusRules subclass that allows basic overrides of focus/activation to
143 // be tested. This is intended more as a test that the override system works at
144 // all, rather than as an exhaustive set of use cases, those should be covered
145 // in tests for those FocusRules implementations.
146 class TestFocusRules : public BasicFocusRules {
147 public:
148 TestFocusRules(View* root)
149 : BasicFocusRules(root), focus_restriction_(NULL) {}
150
151 // Restricts focus and activation to this window and its child hierarchy.
152 void set_focus_restriction(View* focus_restriction) {
153 focus_restriction_ = focus_restriction;
154 }
155
156 // Overridden from BasicFocusRules:
157 bool CanActivateView(View* view) const override {
158 // Restricting focus to a non-activatable child view means the activatable
159 // parent outside the focus restriction is activatable.
160 bool can_activate =
161 CanFocusOrActivate(view) || view->Contains(focus_restriction_);
162 return can_activate ? BasicFocusRules::CanActivateView(view) : false;
163 }
164 bool CanFocusView(View* view) const override {
165 return CanFocusOrActivate(view) ? BasicFocusRules::CanFocusView(view)
166 : false;
167 }
168 View* GetActivatableView(View* view) const override {
169 return BasicFocusRules::GetActivatableView(
170 CanFocusOrActivate(view) ? view : focus_restriction_);
171 }
172 View* GetFocusableView(View* view) const override {
173 return BasicFocusRules::GetFocusableView(
174 CanFocusOrActivate(view) ? view : focus_restriction_);
175 }
176 View* GetNextActivatableView(View* ignore) const override {
177 View* next_activatable = BasicFocusRules::GetNextActivatableView(ignore);
178 return CanFocusOrActivate(next_activatable)
179 ? next_activatable
180 : GetActivatableView(focus_restriction_);
181 }
182
183 private:
184 bool CanFocusOrActivate(View* view) const {
185 return !focus_restriction_ || focus_restriction_->Contains(view);
186 }
187
188 View* focus_restriction_;
189
190 DISALLOW_COPY_AND_ASSIGN(TestFocusRules);
191 };
192
193 // Common infrastructure shared by all FocusController test types.
194 class FocusControllerTestBase : public testing::Test {
195 protected:
196 // Hierarchy used by all tests:
197 // root_window
198 // +-- w1
199 // | +-- w11
200 // | +-- w12
201 // +-- w2
202 // | +-- w21
203 // | +-- w211
204 // +-- w3
205 FocusControllerTestBase()
206 : root_view_(0, gfx::Rect(0, 0, 800, 600)),
207 v1(1, gfx::Rect(0, 0, 50, 50), root_view()),
208 v11(11, gfx::Rect(5, 5, 10, 10), &v1),
209 v12(12, gfx::Rect(15, 15, 10, 10), &v1),
210 v2(2, gfx::Rect(75, 75, 50, 50), root_view()),
211 v21(21, gfx::Rect(5, 5, 10, 10), &v2),
212 v211(211, gfx::Rect(1, 1, 5, 5), &v21),
213 v3(3, gfx::Rect(125, 125, 50, 50), root_view()) {}
214
215 // Overridden from testing::Test:
216 void SetUp() override {
217 testing::Test::SetUp();
218
219 test_focus_rules_ = new TestFocusRules(root_view());
220 focus_controller_.reset(
221 new FocusController(scoped_ptr<FocusRules>(test_focus_rules_)));
222
223 ViewTarget* root_target = root_view_.target();
224 root_target->SetEventTargeter(scoped_ptr<ViewTargeter>(new ViewTargeter()));
225 view_event_dispatcher_.reset(new ViewEventDispatcher());
226 view_event_dispatcher_->SetRootViewTarget(root_target);
227
228 GetRootViewTarget()->AddPreTargetHandler(focus_controller_.get());
229 }
230
231 void TearDown() override {
232 GetRootViewTarget()->RemovePreTargetHandler(focus_controller_.get());
233 view_event_dispatcher_.reset();
234
235 test_focus_rules_ = nullptr; // Owned by FocusController.
236 focus_controller_.reset();
237
238 testing::Test::TearDown();
239 }
240
241 void FocusView(View* view) { focus_controller_->FocusView(view); }
242 View* GetFocusedView() { return focus_controller_->GetFocusedView(); }
243 int GetFocusedViewId() {
244 View* focused_view = GetFocusedView();
245 return focused_view ? focused_view->id() : -1;
246 }
247 void ActivateView(View* view) { focus_controller_->ActivateView(view); }
248 void DeactivateView(View* view) { focus_controller_->DeactivateView(view); }
249 View* GetActiveView() { return focus_controller_->GetActiveView(); }
250 int GetActiveViewId() {
251 View* active_view = GetActiveView();
252 return active_view ? active_view->id() : -1;
253 }
254
255 View* GetViewById(int id) { return root_view_.GetChildById(id); }
256
257 void ClickLeftButton(View* view) {
258 // Get the center bounds of |target| in |root_view_| coordinate space.
259 gfx::Point center =
260 gfx::Rect(view->bounds().To<gfx::Rect>().size()).CenterPoint();
261 ViewTarget::ConvertPointToTarget(ViewTarget::TargetFromView(view),
262 root_view_.target(), &center);
263
264 ui::MouseEvent button_down(ui::ET_MOUSE_PRESSED, center, center,
265 ui::EF_LEFT_MOUSE_BUTTON, ui::EF_NONE);
266 ui::EventDispatchDetails details =
267 view_event_dispatcher_->OnEventFromSource(&button_down);
268 CHECK(!details.dispatcher_destroyed);
269
270 ui::MouseEvent button_up(ui::ET_MOUSE_RELEASED, center, center,
271 ui::EF_LEFT_MOUSE_BUTTON, ui::EF_NONE);
272 details = view_event_dispatcher_->OnEventFromSource(&button_up);
273 CHECK(!details.dispatcher_destroyed);
274 }
275
276 ViewTarget* GetRootViewTarget() {
277 return ViewTarget::TargetFromView(root_view());
278 }
279
280 View* root_view() { return &root_view_; }
281 TestFocusRules* test_focus_rules() { return test_focus_rules_; }
282 FocusController* focus_controller() { return focus_controller_.get(); }
283
284 // Test functions.
285 virtual void BasicFocus() = 0;
286 virtual void BasicActivation() = 0;
287 virtual void FocusEvents() = 0;
288
289 private:
290 TestView root_view_;
291 scoped_ptr<FocusController> focus_controller_;
292 TestFocusRules* test_focus_rules_;
293 // TODO(erg): The aura version of this class also keeps track of WMState. Do
294 // we need something analogous here?
295
296 scoped_ptr<ViewEventDispatcher> view_event_dispatcher_;
297
298 TestView v1;
299 TestView v11;
300 TestView v12;
301 TestView v2;
302 TestView v21;
303 TestView v211;
304 TestView v3;
305
306 DISALLOW_COPY_AND_ASSIGN(FocusControllerTestBase);
307 };
308
309 // Test base for tests where focus is directly set to a target window.
310 class FocusControllerDirectTestBase : public FocusControllerTestBase {
311 protected:
312 FocusControllerDirectTestBase() {}
313
314 // Different test types shift focus in different ways.
315 virtual void FocusViewDirect(View* view) = 0;
316 virtual void ActivateViewDirect(View* view) = 0;
317 virtual void DeactivateViewDirect(View* view) = 0;
318
319 // Input events do not change focus if the window can not be focused.
320 virtual bool IsInputEvent() = 0;
321
322 void FocusViewById(int id) {
323 View* view = root_view()->GetChildById(id);
324 DCHECK(view);
325 FocusViewDirect(view);
326 }
327 void ActivateViewById(int id) {
328 View* view = root_view()->GetChildById(id);
329 DCHECK(view);
330 ActivateViewDirect(view);
331 }
332
333 // Overridden from FocusControllerTestBase:
334 void BasicFocus() override {
335 EXPECT_EQ(nullptr, GetFocusedView());
336 FocusViewById(1);
337 EXPECT_EQ(1, GetFocusedViewId());
338 FocusViewById(2);
339 EXPECT_EQ(2, GetFocusedViewId());
340 }
341 void BasicActivation() override {
342 EXPECT_EQ(nullptr, GetActiveView());
343 ActivateViewById(1);
344 EXPECT_EQ(1, GetActiveViewId());
345 ActivateViewById(2);
346 EXPECT_EQ(2, GetActiveViewId());
347 // Verify that attempting to deactivate NULL does not crash and does not
348 // change activation.
349 DeactivateView(nullptr);
350 EXPECT_EQ(2, GetActiveViewId());
351 DeactivateView(GetActiveView());
352 EXPECT_EQ(1, GetActiveViewId());
353 }
354 void FocusEvents() override {
355 ScopedFocusNotificationObserver root_observer(focus_controller());
356 ScopedFilteringFocusNotificationObserver observer1(focus_controller(),
357 GetViewById(1));
358 ScopedFilteringFocusNotificationObserver observer2(focus_controller(),
359 GetViewById(2));
360
361 root_observer.ExpectCounts(0, 0);
362 observer1.ExpectCounts(0, 0);
363 observer2.ExpectCounts(0, 0);
364
365 FocusViewById(1);
366 root_observer.ExpectCounts(1, 1);
367 observer1.ExpectCounts(1, 1);
368 observer2.ExpectCounts(0, 0);
369
370 FocusViewById(2);
371 root_observer.ExpectCounts(2, 2);
372 observer1.ExpectCounts(2, 2);
373 observer2.ExpectCounts(1, 1);
374 }
375
376 // TODO(erg): There are a whole bunch other tests here. Port them.
377
378 private:
379 DISALLOW_COPY_AND_ASSIGN(FocusControllerDirectTestBase);
380 };
381
382 // Focus and Activation changes via the FocusController API.
383 class FocusControllerApiTest : public FocusControllerDirectTestBase {
384 public:
385 FocusControllerApiTest() {}
386
387 private:
388 // Overridden from FocusControllerTestBase:
389 void FocusViewDirect(View* view) override { FocusView(view); }
390 void ActivateViewDirect(View* view) override { ActivateView(view); }
391 void DeactivateViewDirect(View* view) override { DeactivateView(view); }
392 bool IsInputEvent() override { return false; }
393
394 DISALLOW_COPY_AND_ASSIGN(FocusControllerApiTest);
395 };
396
397 // Focus and Activation changes via input events.
398 class FocusControllerMouseEventTest : public FocusControllerDirectTestBase {
399 public:
400 FocusControllerMouseEventTest() {}
401
402 // Tests that a handled mouse event does not trigger a window activation.
403 void IgnoreHandledEvent() {
404 EXPECT_EQ(NULL, GetActiveView());
405 View* v1 = root_view()->GetChildById(1);
406 SimpleEventHandler handler;
407 GetRootViewTarget()->PrependPreTargetHandler(&handler);
408 ClickLeftButton(v1);
409 EXPECT_EQ(NULL, GetActiveView());
410 // TODO(erg): Add gesture testing when we get gestures working.
411 GetRootViewTarget()->RemovePreTargetHandler(&handler);
412 ClickLeftButton(v1);
413 EXPECT_EQ(1, GetActiveViewId());
414 }
415
416 private:
417 // Overridden from FocusControllerTestBase:
418 void FocusViewDirect(View* view) override { ClickLeftButton(view); }
419 void ActivateViewDirect(View* view) override { ClickLeftButton(view); }
420 void DeactivateViewDirect(View* view) override {
421 View* next_activatable = test_focus_rules()->GetNextActivatableView(view);
422 ClickLeftButton(next_activatable);
423 }
424 bool IsInputEvent() override { return true; }
425
426 DISALLOW_COPY_AND_ASSIGN(FocusControllerMouseEventTest);
427 };
428
429 #define FOCUS_CONTROLLER_TEST(TESTCLASS, TESTNAME) \
430 TEST_F(TESTCLASS, TESTNAME) { TESTNAME(); }
431
432 // Runs direct focus change tests (input events and API calls).
433 //
434 // TODO(erg): Enable gesture events in the future.
435 #define DIRECT_FOCUS_CHANGE_TESTS(TESTNAME) \
436 FOCUS_CONTROLLER_TEST(FocusControllerApiTest, TESTNAME) \
437 FOCUS_CONTROLLER_TEST(FocusControllerMouseEventTest, TESTNAME)
438
439 DIRECT_FOCUS_CHANGE_TESTS(BasicFocus);
440 DIRECT_FOCUS_CHANGE_TESTS(BasicActivation);
441 DIRECT_FOCUS_CHANGE_TESTS(FocusEvents);
442
443 // TODO(erg): Also port IMPLICIT_FOCUS_CHANGE_TARGET_TESTS / ALL_FOCUS_TESTS
444 // here, and replace the above direct testing list.
445
446 // If a mouse event was handled, it should not activate a window.
447 FOCUS_CONTROLLER_TEST(FocusControllerMouseEventTest, IgnoreHandledEvent);
448
449 } // namespace mojo
OLDNEW
« no previous file with comments | « mojo/services/window_manager/focus_controller_observer.h ('k') | mojo/services/window_manager/focus_rules.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698