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 "ash/wm/user_activity_detector.h" 6 7 #include "ash/shell.h" 8 #include "ash/test/ash_test_base.h" 9 #include "ash/wm/user_activity_observer.h" 10 #include "base/compiler_specific.h" 11 #include "base/memory/scoped_ptr.h" 12 #include "base/time/time.h" 13 #include "ui/aura/test/test_windows.h" 14 #include "ui/aura/window.h" 15 #include "ui/events/event.h" 16 #include "ui/events/event_constants.h" 17 #include "ui/events/keycodes/keyboard_codes.h" 18 #include "ui/gfx/point.h" 19 20 namespace { 21 22 void SetEventTarget(ui::EventTarget* target, ui::Event* event) { 23 ui::Event::DispatcherApi dispatch_helper(event); 24 dispatch_helper.set_target(target); 25 } 26 27 } 28 29 namespace ash { 30 namespace test { 31 32 // Implementation that just counts the number of times we've been told that the 33 // user is active. 34 class TestUserActivityObserver : public UserActivityObserver { 35 public: 36 TestUserActivityObserver() : num_invocations_(0) {} 37 38 int num_invocations() const { return num_invocations_; } 39 void reset_stats() { num_invocations_ = 0; } 40 41 // UserActivityObserver implementation. 42 virtual void OnUserActivity(const ui::Event* event) OVERRIDE { 43 num_invocations_++; 44 } 45 46 private: 47 // Number of times that OnUserActivity() has been called. 48 int num_invocations_; 49 50 DISALLOW_COPY_AND_ASSIGN(TestUserActivityObserver); 51 }; 52 53 class UserActivityDetectorTest : public AshTestBase { 54 public: 55 UserActivityDetectorTest() {} 56 virtual ~UserActivityDetectorTest() {} 57 58 virtual void SetUp() OVERRIDE { 59 AshTestBase::SetUp(); 60 observer_.reset(new TestUserActivityObserver); 61 detector_ = Shell::GetInstance()->user_activity_detector(); 62 detector_->AddObserver(observer_.get()); 63 64 now_ = base::TimeTicks::Now(); 65 detector_->set_now_for_test(now_); 66 } 67 68 virtual void TearDown() OVERRIDE { 69 detector_->RemoveObserver(observer_.get()); 70 AshTestBase::TearDown(); 71 } 72 73 protected: 74 // Move |detector_|'s idea of the current time forward by |delta|. 75 void AdvanceTime(base::TimeDelta delta) { 76 now_ += delta; 77 detector_->set_now_for_test(now_); 78 } 79 80 UserActivityDetector* detector_; // not owned 81 82 scoped_ptr<TestUserActivityObserver> observer_; 83 84 base::TimeTicks now_; 85 86 private: 87 DISALLOW_COPY_AND_ASSIGN(UserActivityDetectorTest); 88 }; 89 90 // Checks that the observer is notified in response to different types of input 91 // events. 92 TEST_F(UserActivityDetectorTest, Basic) { 93 scoped_ptr<aura::Window> window(CreateTestWindowInShellWithId(12345)); 94 95 ui::KeyEvent key_event(ui::ET_KEY_PRESSED, ui::VKEY_A, ui::EF_NONE, false); 96 SetEventTarget(window.get(), &key_event); 97 detector_->OnKeyEvent(&key_event); 98 EXPECT_FALSE(key_event.handled()); 99 EXPECT_EQ(now_.ToInternalValue(), 100 detector_->last_activity_time().ToInternalValue()); 101 EXPECT_EQ(1, observer_->num_invocations()); 102 observer_->reset_stats(); 103 104 base::TimeDelta advance_delta = base::TimeDelta::FromMilliseconds( 105 UserActivityDetector::kNotifyIntervalMs); 106 AdvanceTime(advance_delta); 107 ui::MouseEvent mouse_event( 108 ui::ET_MOUSE_MOVED, gfx::Point(), gfx::Point(), ui::EF_NONE); 109 SetEventTarget(window.get(), &mouse_event); 110 detector_->OnMouseEvent(&mouse_event); 111 EXPECT_FALSE(mouse_event.handled()); 112 EXPECT_EQ(now_.ToInternalValue(), 113 detector_->last_activity_time().ToInternalValue()); 114 EXPECT_EQ(1, observer_->num_invocations()); 115 observer_->reset_stats(); 116 117 base::TimeTicks time_before_ignore = now_; 118 119 // Temporarily ignore mouse events when displays are turned on or off. 120 detector_->OnDisplayPowerChanging(); 121 detector_->OnMouseEvent(&mouse_event); 122 EXPECT_FALSE(mouse_event.handled()); 123 EXPECT_EQ(time_before_ignore.ToInternalValue(), 124 detector_->last_activity_time().ToInternalValue()); 125 EXPECT_EQ(0, observer_->num_invocations()); 126 observer_->reset_stats(); 127 128 const base::TimeDelta kIgnoreMouseTime = 129 base::TimeDelta::FromMilliseconds( 130 UserActivityDetector::kDisplayPowerChangeIgnoreMouseMs); 131 AdvanceTime(kIgnoreMouseTime / 2); 132 detector_->OnMouseEvent(&mouse_event); 133 EXPECT_FALSE(mouse_event.handled()); 134 EXPECT_EQ(time_before_ignore.ToInternalValue(), 135 detector_->last_activity_time().ToInternalValue()); 136 EXPECT_EQ(0, observer_->num_invocations()); 137 observer_->reset_stats(); 138 139 // After enough time has passed, mouse events should be reported again. 140 AdvanceTime(std::max(kIgnoreMouseTime, advance_delta)); 141 detector_->OnMouseEvent(&mouse_event); 142 EXPECT_FALSE(mouse_event.handled()); 143 EXPECT_EQ(now_.ToInternalValue(), 144 detector_->last_activity_time().ToInternalValue()); 145 EXPECT_EQ(1, observer_->num_invocations()); 146 observer_->reset_stats(); 147 148 AdvanceTime(advance_delta); 149 ui::TouchEvent touch_event( 150 ui::ET_TOUCH_PRESSED, gfx::Point(), 0, base::TimeDelta()); 151 SetEventTarget(window.get(), &touch_event); 152 detector_->OnTouchEvent(&touch_event); 153 EXPECT_FALSE(touch_event.handled()); 154 EXPECT_EQ(now_.ToInternalValue(), 155 detector_->last_activity_time().ToInternalValue()); 156 EXPECT_EQ(1, observer_->num_invocations()); 157 observer_->reset_stats(); 158 159 AdvanceTime(advance_delta); 160 ui::GestureEvent gesture_event( 161 ui::ET_GESTURE_TAP, 0, 0, ui::EF_NONE, 162 base::TimeDelta::FromMilliseconds(base::Time::Now().ToDoubleT() * 1000), 163 ui::GestureEventDetails(ui::ET_GESTURE_TAP, 0, 0), 0U); 164 SetEventTarget(window.get(), &gesture_event); 165 detector_->OnGestureEvent(&gesture_event); 166 EXPECT_FALSE(gesture_event.handled()); 167 EXPECT_EQ(now_.ToInternalValue(), 168 detector_->last_activity_time().ToInternalValue()); 169 EXPECT_EQ(1, observer_->num_invocations()); 170 observer_->reset_stats(); 171 } 172 173 // Checks that observers aren't notified too frequently. 174 TEST_F(UserActivityDetectorTest, RateLimitNotifications) { 175 scoped_ptr<aura::Window> window(CreateTestWindowInShellWithId(12345)); 176 177 // The observer should be notified about a key event. 178 ui::KeyEvent event(ui::ET_KEY_PRESSED, ui::VKEY_A, ui::EF_NONE, false); 179 SetEventTarget(window.get(), &event); 180 detector_->OnKeyEvent(&event); 181 EXPECT_FALSE(event.handled()); 182 EXPECT_EQ(1, observer_->num_invocations()); 183 observer_->reset_stats(); 184 185 // It shouldn't be notified if a second event occurs 186 // in the same instant in time. 187 detector_->OnKeyEvent(&event); 188 EXPECT_FALSE(event.handled()); 189 EXPECT_EQ(0, observer_->num_invocations()); 190 observer_->reset_stats(); 191 192 // Advance the time, but not quite enough for another notification to be sent. 193 AdvanceTime( 194 base::TimeDelta::FromMilliseconds( 195 UserActivityDetector::kNotifyIntervalMs - 100)); 196 detector_->OnKeyEvent(&event); 197 EXPECT_FALSE(event.handled()); 198 EXPECT_EQ(0, observer_->num_invocations()); 199 observer_->reset_stats(); 200 201 // Advance time by the notification interval, definitely moving out of the 202 // rate limit. This should let us trigger another notification. 203 AdvanceTime(base::TimeDelta::FromMilliseconds( 204 UserActivityDetector::kNotifyIntervalMs)); 205 206 detector_->OnKeyEvent(&event); 207 EXPECT_FALSE(event.handled()); 208 EXPECT_EQ(1, observer_->num_invocations()); 209 } 210 211 // Checks that the detector ignores synthetic mouse events. 212 TEST_F(UserActivityDetectorTest, IgnoreSyntheticMouseEvents) { 213 scoped_ptr<aura::Window> window(CreateTestWindowInShellWithId(12345)); 214 ui::MouseEvent mouse_event( 215 ui::ET_MOUSE_MOVED, gfx::Point(), gfx::Point(), ui::EF_IS_SYNTHESIZED); 216 SetEventTarget(window.get(), &mouse_event); 217 detector_->OnMouseEvent(&mouse_event); 218 EXPECT_FALSE(mouse_event.handled()); 219 EXPECT_EQ(base::TimeTicks().ToInternalValue(), 220 detector_->last_activity_time().ToInternalValue()); 221 EXPECT_EQ(0, observer_->num_invocations()); 222 } 223 224 } // namespace test 225 } // namespace ash 226