blob: c23b74b19c667ee58d462db27c84c619acf18c73 [file] [log] [blame]
// Copyright 2015 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 "chrome/browser/vr/service/vr_device_manager.h"
#include <utility>
#include "base/bind.h"
#include "base/feature_list.h"
#include "base/memory/ptr_util.h"
#include "base/memory/singleton.h"
#include "build/build_config.h"
#include "chrome/common/chrome_features.h"
#include "content/public/common/content_features.h"
#include "content/public/common/service_manager_connection.h"
#include "device/vr/features/features.h"
#include "device/vr/orientation/orientation_device_provider.h"
#include "device/vr/vr_device_provider.h"
#if defined(OS_ANDROID)
#include "device/vr/android/gvr/gvr_device_provider.h"
#endif
#if BUILDFLAG(ENABLE_OPENVR)
#include "device/vr/openvr/openvr_device_provider.h"
#endif
#if BUILDFLAG(ENABLE_OCULUS_VR)
#include "device/vr/oculus/oculus_device_provider.h"
#endif
namespace vr {
namespace {
VRDeviceManager* g_vr_device_manager = nullptr;
} // namespace
VRDeviceManager* VRDeviceManager::GetInstance() {
if (!g_vr_device_manager) {
// Register VRDeviceProviders for the current platform
ProviderList providers;
#if defined(OS_ANDROID)
providers.emplace_back(std::make_unique<device::GvrDeviceProvider>());
#endif
#if BUILDFLAG(ENABLE_OPENVR)
if (base::FeatureList::IsEnabled(features::kOpenVR))
providers.emplace_back(std::make_unique<device::OpenVRDeviceProvider>());
#endif
#if BUILDFLAG(ENABLE_OCULUS_VR)
providers.emplace_back(std::make_unique<device::OculusVRDeviceProvider>());
#endif
if (base::FeatureList::IsEnabled(features::kWebXrOrientationSensorDevice)) {
content::ServiceManagerConnection* connection =
content::ServiceManagerConnection::GetForProcess();
if (connection) {
providers.emplace_back(
std::make_unique<device::VROrientationDeviceProvider>(
connection->GetConnector()));
}
}
new VRDeviceManager(std::move(providers));
}
return g_vr_device_manager;
}
bool VRDeviceManager::HasInstance() {
return g_vr_device_manager != nullptr;
}
VRDeviceManager::VRDeviceManager(ProviderList providers)
: providers_(std::move(providers)) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
CHECK(!g_vr_device_manager);
g_vr_device_manager = this;
}
VRDeviceManager::~VRDeviceManager() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
g_vr_device_manager = nullptr;
}
void VRDeviceManager::AddService(VRServiceImpl* service) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
// Loop through any currently active devices and send Connected messages to
// the service. Future devices that come online will send a Connected message
// when they are created.
InitializeProviders();
for (const DeviceMap::value_type& map_entry : devices_) {
if (!map_entry.second->IsFallbackDevice() || devices_.size() == 1)
service->ConnectDevice(map_entry.second);
}
if (AreAllProvidersInitialized())
service->InitializationComplete();
services_.insert(service);
}
void VRDeviceManager::RemoveService(VRServiceImpl* service) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
services_.erase(service);
if (services_.empty()) {
// Delete the device manager when it has no active connections.
delete g_vr_device_manager;
}
}
void VRDeviceManager::AddDevice(device::VRDevice* device) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(devices_.find(device->GetId()) == devices_.end());
// Ignore any devices with VR_DEVICE_LAST_ID, which is used to prevent
// wraparound of device ids.
if (device->GetId() == device::VR_DEVICE_LAST_ID)
return;
// If we were previously using a fallback device, remove it.
// TODO(offenwanger): This has the potential to cause device change events to
// fire in rapid succession. This should be discussed and resolved when we
// start to actually add and remove devices.
if (devices_.size() == 1 && devices_.begin()->second->IsFallbackDevice()) {
device::VRDevice* device = devices_.begin()->second;
for (VRServiceImpl* service : services_)
service->RemoveDevice(device);
}
devices_[device->GetId()] = device;
if (!device->IsFallbackDevice() || devices_.size() == 1) {
for (VRServiceImpl* service : services_)
service->ConnectDevice(device);
}
}
void VRDeviceManager::RemoveDevice(device::VRDevice* device) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
if (device->GetId() == device::VR_DEVICE_LAST_ID)
return;
auto it = devices_.find(device->GetId());
DCHECK(it != devices_.end());
for (VRServiceImpl* service : services_)
service->RemoveDevice(device);
devices_.erase(it);
if (devices_.size() == 1 && devices_.begin()->second->IsFallbackDevice()) {
device::VRDevice* device = devices_.begin()->second;
for (VRServiceImpl* service : services_)
service->ConnectDevice(device);
}
}
device::VRDevice* VRDeviceManager::GetDevice(unsigned int index) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
if (index == 0)
return nullptr;
DeviceMap::iterator iter = devices_.find(index);
if (iter == devices_.end())
return nullptr;
return iter->second;
}
void VRDeviceManager::InitializeProviders() {
if (providers_initialized_)
return;
for (const auto& provider : providers_) {
provider->Initialize(
base::Bind(&VRDeviceManager::AddDevice, base::Unretained(this)),
base::Bind(&VRDeviceManager::RemoveDevice, base::Unretained(this)),
base::BindOnce(&VRDeviceManager::OnProviderInitialized,
base::Unretained(this)));
}
providers_initialized_ = true;
}
void VRDeviceManager::OnProviderInitialized() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
++num_initialized_providers_;
if (AreAllProvidersInitialized()) {
for (VRServiceImpl* service : services_)
service->InitializationComplete();
}
}
bool VRDeviceManager::AreAllProvidersInitialized() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
return num_initialized_providers_ == providers_.size();
}
size_t VRDeviceManager::NumberOfConnectedServices() {
return services_.size();
}
} // namespace vr