blob: d07fc29d49a479c8efb886cf9efbdb7e6626df12 [file] [log] [blame]
// Copyright 2019 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 "third_party/blink/renderer/modules/device_orientation/device_sensor_entry.h"
#include "services/device/public/cpp/generic_sensor/sensor_reading.h"
#include "services/device/public/cpp/generic_sensor/sensor_reading_shared_buffer_reader.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/modules/device_orientation/device_sensor_event_pump.h"
#include "third_party/blink/renderer/platform/heap/persistent.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
namespace blink {
DeviceSensorEntry::DeviceSensorEntry(DeviceSensorEventPump* event_pump,
ExecutionContext* context,
device::mojom::blink::SensorType type)
: event_pump_(event_pump),
sensor_remote_(context),
client_receiver_(this, context),
type_(type) {}
DeviceSensorEntry::~DeviceSensorEntry() = default;
void DeviceSensorEntry::Start(
device::mojom::blink::SensorProvider* sensor_provider) {
if (state_ == State::NOT_INITIALIZED) {
state_ = State::INITIALIZING;
sensor_provider->GetSensor(type_,
WTF::Bind(&DeviceSensorEntry::OnSensorCreated,
WrapWeakPersistent(this)));
} else if (state_ == State::SUSPENDED) {
sensor_remote_->Resume();
state_ = State::ACTIVE;
event_pump_->DidStartIfPossible();
} else if (state_ == State::SHOULD_SUSPEND) {
// This can happen when calling Start(), Stop(), Start() in a sequence:
// After the first Start() call, the sensor state is
// State::INITIALIZING. Then after the Stop() call, the sensor
// state is State::SHOULD_SUSPEND, and the next Start() call needs
// to set the sensor state to be State::INITIALIZING again.
state_ = State::INITIALIZING;
} else {
NOTREACHED();
}
}
void DeviceSensorEntry::Stop() {
if (sensor_remote_.is_bound()) {
sensor_remote_->Suspend();
state_ = State::SUSPENDED;
} else if (state_ == State::INITIALIZING) {
// When the sensor needs to be suspended, and it is still in the
// State::INITIALIZING state, the sensor creation is not affected
// (the DeviceSensorEntry::OnSensorCreated() callback will run as usual),
// but the sensor is marked as State::SHOULD_SUSPEND, and when the sensor is
// created successfully, it will be suspended and its state will be marked
// as State::SUSPENDED in the DeviceSensorEntry::OnSensorAddConfiguration().
state_ = State::SHOULD_SUSPEND;
}
}
bool DeviceSensorEntry::IsConnected() const {
return sensor_remote_.is_bound();
}
bool DeviceSensorEntry::ReadyOrErrored() const {
// When some sensors are not available, the pump still needs to fire
// events which set the unavailable sensor data fields to null.
return state_ == State::ACTIVE || state_ == State::NOT_INITIALIZED;
}
bool DeviceSensorEntry::GetReading(device::SensorReading* reading) {
if (!sensor_remote_.is_bound())
return false;
DCHECK(shared_buffer_reader_);
if (!shared_buffer_reader_->GetReading(reading)) {
HandleSensorError();
return false;
}
return true;
}
void DeviceSensorEntry::Trace(Visitor* visitor) const {
visitor->Trace(event_pump_);
visitor->Trace(sensor_remote_);
visitor->Trace(client_receiver_);
}
void DeviceSensorEntry::RaiseError() {
HandleSensorError();
}
void DeviceSensorEntry::SensorReadingChanged() {
// Since DeviceSensorEventPump::FireEvent is called in a fixed
// frequency, the |shared_buffer| is read frequently, and
// Sensor::ConfigureReadingChangeNotifications() is set to false,
// so this method is not called and doesn't need to be implemented.
NOTREACHED();
}
void DeviceSensorEntry::OnSensorCreated(
device::mojom::blink::SensorCreationResult result,
device::mojom::blink::SensorInitParamsPtr params) {
// |state_| can be State::SHOULD_SUSPEND if Stop() is called
// before OnSensorCreated() is called.
DCHECK(state_ == State::INITIALIZING || state_ == State::SHOULD_SUSPEND);
if (!params) {
HandleSensorError();
event_pump_->DidStartIfPossible();
return;
}
DCHECK_EQ(device::mojom::SensorCreationResult::SUCCESS, result);
constexpr size_t kReadBufferSize = sizeof(device::SensorReadingSharedBuffer);
DCHECK_EQ(0u, params->buffer_offset % kReadBufferSize);
sensor_remote_.Bind(std::move(params->sensor), event_pump_->task_runner_);
client_receiver_.Bind(std::move(params->client_receiver),
event_pump_->task_runner_);
shared_buffer_reader_ = device::SensorReadingSharedBufferReader::Create(
std::move(params->memory), params->buffer_offset);
if (!shared_buffer_reader_) {
HandleSensorError();
event_pump_->DidStartIfPossible();
return;
}
device::mojom::blink::SensorConfigurationPtr config =
std::move(params->default_configuration);
config->frequency = std::min(
static_cast<double>(DeviceSensorEventPump::kDefaultPumpFrequencyHz),
params->maximum_frequency);
sensor_remote_.set_disconnect_handler(WTF::Bind(
&DeviceSensorEntry::HandleSensorError, WrapWeakPersistent(this)));
sensor_remote_->ConfigureReadingChangeNotifications(/*enabled=*/false);
sensor_remote_->AddConfiguration(
std::move(config), WTF::Bind(&DeviceSensorEntry::OnSensorAddConfiguration,
WrapWeakPersistent(this)));
}
void DeviceSensorEntry::OnSensorAddConfiguration(bool success) {
if (!success)
HandleSensorError();
if (state_ == State::INITIALIZING) {
state_ = State::ACTIVE;
event_pump_->DidStartIfPossible();
} else if (state_ == State::SHOULD_SUSPEND) {
sensor_remote_->Suspend();
state_ = State::SUSPENDED;
}
}
void DeviceSensorEntry::HandleSensorError() {
sensor_remote_.reset();
state_ = State::NOT_INITIALIZED;
shared_buffer_reader_.reset();
client_receiver_.reset();
}
} // namespace blink