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 "base/command_line.h" 6 #include "base/synchronization/waitable_event.h" 7 #include "base/threading/platform_thread.h" 8 #include "content/browser/device_sensors/data_fetcher_shared_memory.h" 9 #include "content/browser/device_sensors/device_inertial_sensor_service.h" 10 #include "content/common/device_sensors/device_light_hardware_buffer.h" 11 #include "content/common/device_sensors/device_motion_hardware_buffer.h" 12 #include "content/common/device_sensors/device_orientation_hardware_buffer.h" 13 #include "content/public/browser/browser_thread.h" 14 #include "content/public/browser/web_contents.h" 15 #include "content/public/common/content_switches.h" 16 #include "content/public/test/content_browser_test.h" 17 #include "content/public/test/content_browser_test_utils.h" 18 #include "content/public/test/test_navigation_observer.h" 19 #include "content/public/test/test_utils.h" 20 #include "content/shell/browser/shell.h" 21 #include "content/shell/browser/shell_javascript_dialog_manager.h" 22 23 namespace content { 24 25 namespace { 26 27 class FakeDataFetcher : public DataFetcherSharedMemory { 28 public: 29 FakeDataFetcher() 30 : started_orientation_(false, false), 31 stopped_orientation_(false, false), 32 started_motion_(false, false), 33 stopped_motion_(false, false), 34 started_light_(false, false), 35 stopped_light_(false, false), 36 sensor_data_available_(true) {} 37 virtual ~FakeDataFetcher() { } 38 39 virtual bool Start(ConsumerType consumer_type, void* buffer) OVERRIDE { 40 EXPECT_TRUE(buffer); 41 42 switch (consumer_type) { 43 case CONSUMER_TYPE_MOTION: 44 { 45 DeviceMotionHardwareBuffer* motion_buffer = 46 static_cast<DeviceMotionHardwareBuffer*>(buffer); 47 if (sensor_data_available_) 48 UpdateMotion(motion_buffer); 49 SetMotionBufferReady(motion_buffer); 50 started_motion_.Signal(); 51 } 52 break; 53 case CONSUMER_TYPE_ORIENTATION: 54 { 55 DeviceOrientationHardwareBuffer* orientation_buffer = 56 static_cast<DeviceOrientationHardwareBuffer*>(buffer); 57 if (sensor_data_available_) 58 UpdateOrientation(orientation_buffer); 59 SetOrientationBufferReady(orientation_buffer); 60 started_orientation_.Signal(); 61 } 62 break; 63 case CONSUMER_TYPE_LIGHT: 64 { 65 DeviceLightHardwareBuffer* light_buffer = 66 static_cast<DeviceLightHardwareBuffer*>(buffer); 67 UpdateLight(light_buffer, 68 sensor_data_available_ 69 ? 100 70 : std::numeric_limits<double>::infinity()); 71 started_light_.Signal(); 72 } 73 break; 74 default: 75 return false; 76 } 77 return true; 78 } 79 80 virtual bool Stop(ConsumerType consumer_type) OVERRIDE { 81 switch (consumer_type) { 82 case CONSUMER_TYPE_MOTION: 83 stopped_motion_.Signal(); 84 break; 85 case CONSUMER_TYPE_ORIENTATION: 86 stopped_orientation_.Signal(); 87 break; 88 case CONSUMER_TYPE_LIGHT: 89 stopped_light_.Signal(); 90 break; 91 default: 92 return false; 93 } 94 return true; 95 } 96 97 virtual void Fetch(unsigned consumer_bitmask) OVERRIDE { 98 FAIL() << "fetch should not be called"; 99 } 100 101 virtual FetcherType GetType() const OVERRIDE { 102 return FETCHER_TYPE_DEFAULT; 103 } 104 105 void SetSensorDataAvailable(bool available) { 106 sensor_data_available_ = available; 107 } 108 109 void SetMotionBufferReady(DeviceMotionHardwareBuffer* buffer) { 110 buffer->seqlock.WriteBegin(); 111 buffer->data.allAvailableSensorsAreActive = true; 112 buffer->seqlock.WriteEnd(); 113 } 114 115 void SetOrientationBufferReady(DeviceOrientationHardwareBuffer* buffer) { 116 buffer->seqlock.WriteBegin(); 117 buffer->data.allAvailableSensorsAreActive = true; 118 buffer->seqlock.WriteEnd(); 119 } 120 121 void UpdateMotion(DeviceMotionHardwareBuffer* buffer) { 122 buffer->seqlock.WriteBegin(); 123 buffer->data.accelerationX = 1; 124 buffer->data.hasAccelerationX = true; 125 buffer->data.accelerationY = 2; 126 buffer->data.hasAccelerationY = true; 127 buffer->data.accelerationZ = 3; 128 buffer->data.hasAccelerationZ = true; 129 130 buffer->data.accelerationIncludingGravityX = 4; 131 buffer->data.hasAccelerationIncludingGravityX = true; 132 buffer->data.accelerationIncludingGravityY = 5; 133 buffer->data.hasAccelerationIncludingGravityY = true; 134 buffer->data.accelerationIncludingGravityZ = 6; 135 buffer->data.hasAccelerationIncludingGravityZ = true; 136 137 buffer->data.rotationRateAlpha = 7; 138 buffer->data.hasRotationRateAlpha = true; 139 buffer->data.rotationRateBeta = 8; 140 buffer->data.hasRotationRateBeta = true; 141 buffer->data.rotationRateGamma = 9; 142 buffer->data.hasRotationRateGamma = true; 143 144 buffer->data.interval = 100; 145 buffer->data.allAvailableSensorsAreActive = true; 146 buffer->seqlock.WriteEnd(); 147 } 148 149 void UpdateOrientation(DeviceOrientationHardwareBuffer* buffer) { 150 buffer->seqlock.WriteBegin(); 151 buffer->data.alpha = 1; 152 buffer->data.hasAlpha = true; 153 buffer->data.beta = 2; 154 buffer->data.hasBeta = true; 155 buffer->data.gamma = 3; 156 buffer->data.hasGamma = true; 157 buffer->data.allAvailableSensorsAreActive = true; 158 buffer->seqlock.WriteEnd(); 159 } 160 161 void UpdateLight(DeviceLightHardwareBuffer* buffer, double lux) { 162 buffer->seqlock.WriteBegin(); 163 buffer->data.value = lux; 164 buffer->seqlock.WriteEnd(); 165 } 166 167 base::WaitableEvent started_orientation_; 168 base::WaitableEvent stopped_orientation_; 169 base::WaitableEvent started_motion_; 170 base::WaitableEvent stopped_motion_; 171 base::WaitableEvent started_light_; 172 base::WaitableEvent stopped_light_; 173 bool sensor_data_available_; 174 175 private: 176 DISALLOW_COPY_AND_ASSIGN(FakeDataFetcher); 177 }; 178 179 180 class DeviceInertialSensorBrowserTest : public ContentBrowserTest { 181 public: 182 DeviceInertialSensorBrowserTest() 183 : fetcher_(NULL), 184 io_loop_finished_event_(false, false) { 185 } 186 187 virtual void SetUpOnMainThread() OVERRIDE { 188 BrowserThread::PostTask( 189 BrowserThread::IO, FROM_HERE, 190 base::Bind(&DeviceInertialSensorBrowserTest::SetUpOnIOThread, this)); 191 io_loop_finished_event_.Wait(); 192 } 193 194 void SetUpOnIOThread() { 195 fetcher_ = new FakeDataFetcher(); 196 DeviceInertialSensorService::GetInstance()-> 197 SetDataFetcherForTesting(fetcher_); 198 io_loop_finished_event_.Signal(); 199 } 200 201 void DelayAndQuit(base::TimeDelta delay) { 202 base::PlatformThread::Sleep(delay); 203 base::MessageLoop::current()->QuitWhenIdle(); 204 } 205 206 void WaitForAlertDialogAndQuitAfterDelay(base::TimeDelta delay) { 207 ShellJavaScriptDialogManager* dialog_manager= 208 static_cast<ShellJavaScriptDialogManager*>( 209 shell()->GetJavaScriptDialogManager()); 210 211 scoped_refptr<MessageLoopRunner> runner = new MessageLoopRunner(); 212 dialog_manager->set_dialog_request_callback( 213 base::Bind(&DeviceInertialSensorBrowserTest::DelayAndQuit, this, 214 delay)); 215 runner->Run(); 216 } 217 218 FakeDataFetcher* fetcher_; 219 220 private: 221 base::WaitableEvent io_loop_finished_event_; 222 }; 223 224 IN_PROC_BROWSER_TEST_F(DeviceInertialSensorBrowserTest, OrientationTest) { 225 // The test page will register an event handler for orientation events, 226 // expects to get an event with fake values, then removes the event 227 // handler and navigates to #pass. 228 GURL test_url = GetTestUrl("device_sensors", "device_orientation_test.html"); 229 NavigateToURLBlockUntilNavigationsComplete(shell(), test_url, 2); 230 231 EXPECT_EQ("pass", shell()->web_contents()->GetLastCommittedURL().ref()); 232 fetcher_->started_orientation_.Wait(); 233 fetcher_->stopped_orientation_.Wait(); 234 } 235 236 IN_PROC_BROWSER_TEST_F(DeviceInertialSensorBrowserTest, LightTest) { 237 // The test page will register an event handler for light events, 238 // expects to get an event with fake values, then removes the event 239 // handler and navigates to #pass. 240 GURL test_url = GetTestUrl("device_sensors", "device_light_test.html"); 241 242 // TODO(riju): remove command line args when the feature goes stable. 243 if (!CommandLine::ForCurrentProcess()->HasSwitch( 244 switches::kEnableExperimentalWebPlatformFeatures)) { 245 CommandLine::ForCurrentProcess()->AppendSwitch( 246 switches::kEnableExperimentalWebPlatformFeatures); 247 } 248 249 NavigateToURLBlockUntilNavigationsComplete(shell(), test_url, 2); 250 251 EXPECT_EQ("pass", shell()->web_contents()->GetLastCommittedURL().ref()); 252 fetcher_->started_light_.Wait(); 253 fetcher_->stopped_light_.Wait(); 254 } 255 256 IN_PROC_BROWSER_TEST_F(DeviceInertialSensorBrowserTest, MotionTest) { 257 // The test page will register an event handler for motion events, 258 // expects to get an event with fake values, then removes the event 259 // handler and navigates to #pass. 260 GURL test_url = GetTestUrl("device_sensors", "device_motion_test.html"); 261 NavigateToURLBlockUntilNavigationsComplete(shell(), test_url, 2); 262 263 EXPECT_EQ("pass", shell()->web_contents()->GetLastCommittedURL().ref()); 264 fetcher_->started_motion_.Wait(); 265 fetcher_->stopped_motion_.Wait(); 266 } 267 268 // crbug/416406. The test is flaky. 269 IN_PROC_BROWSER_TEST_F(DeviceInertialSensorBrowserTest, 270 DISABLED_LightOneOffInfintyTest) { 271 // The test page will register an event handler for light events, 272 // expects to get an event with value equal to Infinity. This tests that the 273 // one-off infinity event still propagates to window after the alert is 274 // dismissed and the callback is invoked which navigates to #pass. 275 fetcher_->SetSensorDataAvailable(false); 276 277 // TODO(riju): remove command line args when the feature goes stable. 278 if (!CommandLine::ForCurrentProcess()->HasSwitch( 279 switches::kEnableExperimentalWebPlatformFeatures)) { 280 CommandLine::ForCurrentProcess()->AppendSwitch( 281 switches::kEnableExperimentalWebPlatformFeatures); 282 } 283 284 TestNavigationObserver same_tab_observer(shell()->web_contents(), 2); 285 286 GURL test_url = 287 GetTestUrl("device_sensors", "device_light_infinity_test.html"); 288 shell()->LoadURL(test_url); 289 290 WaitForAlertDialogAndQuitAfterDelay(base::TimeDelta::FromMilliseconds(1000)); 291 292 fetcher_->started_light_.Wait(); 293 fetcher_->stopped_light_.Wait(); 294 same_tab_observer.Wait(); 295 EXPECT_EQ("pass", shell()->web_contents()->GetLastCommittedURL().ref()); 296 } 297 298 // Flaking in the android try bot. See http://crbug.com/360578. 299 #if defined(OS_ANDROID) 300 #define MAYBE_OrientationNullTestWithAlert DISABLED_OrientationNullTestWithAlert 301 #else 302 #define MAYBE_OrientationNullTestWithAlert OrientationNullTestWithAlert 303 #endif 304 IN_PROC_BROWSER_TEST_F(DeviceInertialSensorBrowserTest, 305 MAYBE_OrientationNullTestWithAlert) { 306 // The test page will register an event handler for orientation events, 307 // expects to get an event with null values. The test raises a modal alert 308 // dialog with a delay to test that the one-off null-event still propagates 309 // to window after the alert is dismissed and the callback is invoked which 310 // navigates to #pass. 311 fetcher_->SetSensorDataAvailable(false); 312 TestNavigationObserver same_tab_observer(shell()->web_contents(), 2); 313 314 GURL test_url = GetTestUrl("device_sensors", 315 "device_orientation_null_test_with_alert.html"); 316 shell()->LoadURL(test_url); 317 318 // TODO(timvolodine): investigate if it is possible to test this without 319 // delay, crbug.com/360044. 320 WaitForAlertDialogAndQuitAfterDelay(base::TimeDelta::FromMilliseconds(1000)); 321 322 fetcher_->started_orientation_.Wait(); 323 fetcher_->stopped_orientation_.Wait(); 324 same_tab_observer.Wait(); 325 EXPECT_EQ("pass", shell()->web_contents()->GetLastCommittedURL().ref()); 326 } 327 328 // Flaking in the android try bot. See http://crbug.com/360578. 329 #if defined(OS_ANDROID) 330 #define MAYBE_MotionNullTestWithAlert DISABLED_MotionNullTestWithAlert 331 #else 332 #define MAYBE_MotionNullTestWithAlert MotionNullTestWithAlert 333 #endif 334 IN_PROC_BROWSER_TEST_F(DeviceInertialSensorBrowserTest, 335 MAYBE_MotionNullTestWithAlert) { 336 // The test page will register an event handler for motion events, 337 // expects to get an event with null values. The test raises a modal alert 338 // dialog with a delay to test that the one-off null-event still propagates 339 // to window after the alert is dismissed and the callback is invoked which 340 // navigates to #pass. 341 fetcher_->SetSensorDataAvailable(false); 342 TestNavigationObserver same_tab_observer(shell()->web_contents(), 2); 343 344 GURL test_url = 345 GetTestUrl("device_sensors", "device_motion_null_test_with_alert.html"); 346 shell()->LoadURL(test_url); 347 348 // TODO(timvolodine): investigate if it is possible to test this without 349 // delay, crbug.com/360044. 350 WaitForAlertDialogAndQuitAfterDelay(base::TimeDelta::FromMilliseconds(1000)); 351 352 fetcher_->started_motion_.Wait(); 353 fetcher_->stopped_motion_.Wait(); 354 same_tab_observer.Wait(); 355 EXPECT_EQ("pass", shell()->web_contents()->GetLastCommittedURL().ref()); 356 } 357 358 } // namespace 359 360 } // namespace content 361