| OLD | NEW |
| (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(), ¢er); | |
| 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 | |
| OLD | NEW |