blob: bebbc7145af1f77166d49872b3198cc25b35d8d1 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/renderer/device_sensors/device_motion_event_pump.h"
#include <cmath>
#include "base/logging.h"
#include "content/public/renderer/render_frame.h"
#include "content/public/renderer/render_thread.h"
#include "content/renderer/render_thread_impl.h"
#include "device/sensors/public/cpp/motion_data.h"
#include "services/device/public/interfaces/sensor.mojom.h"
#include "services/service_manager/public/cpp/interface_provider.h"
#include "ui/gfx/geometry/angle_conversions.h"
namespace content {
DeviceMotionEventPump::DeviceMotionEventPump(RenderThread* thread)
: DeviceSensorEventPump<blink::WebDeviceMotionListener>(thread),
accelerometer_(this, device::mojom::SensorType::ACCELEROMETER),
linear_acceleration_sensor_(
this,
device::mojom::SensorType::LINEAR_ACCELERATION),
gyroscope_(this, device::mojom::SensorType::GYROSCOPE) {}
DeviceMotionEventPump::~DeviceMotionEventPump() {}
void DeviceMotionEventPump::SendStartMessage() {
// When running layout tests, those observers should not listen to the
// actual hardware changes. In order to make that happen, don't connect
// the other end of the mojo pipe to anything.
//
// TODO(sammc): Remove this when JS layout test support for shared buffers
// is ready and the layout tests are converted to use that for mocking.
// https://crbug.com/774183
if (!RenderThreadImpl::current() ||
RenderThreadImpl::current()->layout_test_mode()) {
return;
}
SendStartMessageImpl();
}
void DeviceMotionEventPump::SendStopMessage() {
// SendStopMessage() gets called both when the page visibility changes and if
// all device motion event listeners are unregistered. Since removing the
// event listener is more rare than the page visibility changing,
// Sensor::Suspend() is used to optimize this case for not doing extra work.
accelerometer_.Stop();
linear_acceleration_sensor_.Stop();
gyroscope_.Stop();
}
void DeviceMotionEventPump::SendFakeDataForTesting(void* fake_data) {
if (!listener())
return;
device::MotionData data = *static_cast<device::MotionData*>(fake_data);
listener()->DidChangeDeviceMotion(data);
}
void DeviceMotionEventPump::FireEvent() {
device::MotionData data;
// The device orientation spec states that interval should be in milliseconds.
// https://w3c.github.io/deviceorientation/spec-source-orientation.html#devicemotion
data.interval = kDefaultPumpDelayMicroseconds / 1000;
DCHECK(listener());
GetDataFromSharedMemory(&data);
if (ShouldFireEvent(data))
listener()->DidChangeDeviceMotion(data);
}
void DeviceMotionEventPump::SendStartMessageImpl() {
if (!sensor_provider_) {
RenderFrame* const render_frame = GetRenderFrame();
if (!render_frame)
return;
render_frame->GetRemoteInterfaces()->GetInterface(
mojo::MakeRequest(&sensor_provider_));
sensor_provider_.set_connection_error_handler(
base::Bind(&DeviceSensorEventPump::HandleSensorProviderError,
base::Unretained(this)));
}
accelerometer_.Start(sensor_provider_.get());
linear_acceleration_sensor_.Start(sensor_provider_.get());
gyroscope_.Start(sensor_provider_.get());
}
bool DeviceMotionEventPump::SensorsReadyOrErrored() const {
return accelerometer_.ReadyOrErrored() &&
linear_acceleration_sensor_.ReadyOrErrored() &&
gyroscope_.ReadyOrErrored();
}
void DeviceMotionEventPump::GetDataFromSharedMemory(device::MotionData* data) {
// "Active" here means that sensor has been initialized and is either ready
// or not available.
bool accelerometer_active = true;
bool linear_acceleration_sensor_active = true;
bool gyroscope_active = true;
if (accelerometer_.SensorReadingCouldBeRead() &&
(accelerometer_active = accelerometer_.reading.timestamp() != 0.0)) {
data->acceleration_including_gravity_x = accelerometer_.reading.accel.x;
data->acceleration_including_gravity_y = accelerometer_.reading.accel.y;
data->acceleration_including_gravity_z = accelerometer_.reading.accel.z;
data->has_acceleration_including_gravity_x =
!std::isnan(accelerometer_.reading.accel.x.value());
data->has_acceleration_including_gravity_y =
!std::isnan(accelerometer_.reading.accel.y.value());
data->has_acceleration_including_gravity_z =
!std::isnan(accelerometer_.reading.accel.z.value());
}
if (linear_acceleration_sensor_.SensorReadingCouldBeRead() &&
(linear_acceleration_sensor_active =
linear_acceleration_sensor_.reading.timestamp() != 0.0)) {
data->acceleration_x = linear_acceleration_sensor_.reading.accel.x;
data->acceleration_y = linear_acceleration_sensor_.reading.accel.y;
data->acceleration_z = linear_acceleration_sensor_.reading.accel.z;
data->has_acceleration_x =
!std::isnan(linear_acceleration_sensor_.reading.accel.x.value());
data->has_acceleration_y =
!std::isnan(linear_acceleration_sensor_.reading.accel.y.value());
data->has_acceleration_z =
!std::isnan(linear_acceleration_sensor_.reading.accel.z.value());
}
if (gyroscope_.SensorReadingCouldBeRead() &&
(gyroscope_active = gyroscope_.reading.timestamp() != 0.0)) {
data->rotation_rate_alpha = gfx::RadToDeg(gyroscope_.reading.gyro.x);
data->rotation_rate_beta = gfx::RadToDeg(gyroscope_.reading.gyro.y);
data->rotation_rate_gamma = gfx::RadToDeg(gyroscope_.reading.gyro.z);
data->has_rotation_rate_alpha =
!std::isnan(gyroscope_.reading.gyro.x.value());
data->has_rotation_rate_beta =
!std::isnan(gyroscope_.reading.gyro.y.value());
data->has_rotation_rate_gamma =
!std::isnan(gyroscope_.reading.gyro.z.value());
}
data->all_available_sensors_are_active = accelerometer_active &&
linear_acceleration_sensor_active &&
gyroscope_active;
} // namespace content
bool DeviceMotionEventPump::ShouldFireEvent(
const device::MotionData& data) const {
return data.all_available_sensors_are_active;
}
} // namespace content