Home | History | Annotate | Download | only in device_sensors
      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