VR: Allow VRDeviceProviders to initialize asynchronously

Also implements adding and removing of devices after initialization.

Bug: 695937
Cq-Include-Trybots: master.tryserver.chromium.android:android_optional_gpu_tests_rel;master.tryserver.chromium.linux:linux_optional_gpu_tests_rel;master.tryserver.chromium.mac:mac_optional_gpu_tests_rel;master.tryserver.chromium.win:win_optional_gpu_tests_rel
Change-Id: I70ff4085242720f135da3d3cd51dd99dcbd7492c
Reviewed-on: https://chromium-review.googlesource.com/789652
Commit-Queue: Michael Thiessen <mthiesse@chromium.org>
Reviewed-by: Brandon Jones <bajones@chromium.org>
Reviewed-by: Bill Orr <billorr@chromium.org>
Cr-Commit-Position: refs/heads/master@{#520208}
diff --git a/chrome/browser/vr/service/vr_device_manager.cc b/chrome/browser/vr/service/vr_device_manager.cc
index ac9e0620..1fcc1ba 100644
--- a/chrome/browser/vr/service/vr_device_manager.cc
+++ b/chrome/browser/vr/service/vr_device_manager.cc
@@ -12,6 +12,7 @@
 #include "build/build_config.h"
 #include "chrome/common/chrome_features.h"
 #include "device/vr/features/features.h"
+#include "device/vr/vr_device_provider.h"
 
 #if defined(OS_ANDROID)
 #include "device/vr/android/gvr/gvr_device_provider.h"
@@ -59,36 +60,25 @@
   g_vr_device_manager = nullptr;
 }
 
-void VRDeviceManager::AddService(
-    VRServiceImpl* service,
-    device::mojom::VRService::SetClientCallback callback) {
+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.
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
   InitializeProviders();
 
-  std::vector<device::VRDevice*> devices;
-  for (const auto& provider : providers_)
-    provider->GetDevices(&devices);
+  for (const DeviceMap::value_type& map_entry : devices_)
+    service->ConnectDevice(map_entry.second);
 
-  for (auto* device : devices) {
-    if (device->GetId() == device::VR_DEVICE_LAST_ID)
-      continue;
-
-    if (devices_.find(device->GetId()) == devices_.end())
-      devices_[device->GetId()] = device;
-
-    service->ConnectDevice(device);
-  }
+  if (AreAllProvidersInitialized())
+    service->InitializationComplete();
 
   services_.insert(service);
-
-  std::move(callback).Run();
 }
 
 void VRDeviceManager::RemoveService(VRServiceImpl* service) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   services_.erase(service);
 
   if (services_.empty()) {
@@ -97,6 +87,32 @@
   }
 }
 
+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;
+
+  devices_[device->GetId()] = device;
+  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);
+}
+
 device::VRDevice* VRDeviceManager::GetDevice(unsigned int index) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
@@ -111,13 +127,32 @@
 }
 
 void VRDeviceManager::InitializeProviders() {
-  if (vr_initialized_)
+  if (providers_initialized_)
     return;
 
-  for (const auto& provider : providers_)
-    provider->Initialize();
+  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)));
+  }
 
-  vr_initialized_ = true;
+  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() {
diff --git a/chrome/browser/vr/service/vr_device_manager.h b/chrome/browser/vr/service/vr_device_manager.h
index 3fd614e..a4aca391 100644
--- a/chrome/browser/vr/service/vr_device_manager.h
+++ b/chrome/browser/vr/service/vr_device_manager.h
@@ -18,10 +18,13 @@
 #include "base/timer/timer.h"
 #include "chrome/browser/vr/service/vr_service_impl.h"
 #include "device/vr/vr_device.h"
-#include "device/vr/vr_device_provider.h"
 #include "device/vr/vr_service.mojom.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
 
+namespace device {
+class VRDeviceProvider;
+}
+
 namespace vr {
 
 // Singleton used to provide the platform's VR devices to VRServiceImpl
@@ -39,8 +42,7 @@
   // Automatically connects all currently available VR devices by querying
   // the device providers and, for each returned device, calling
   // VRServiceImpl::ConnectDevice.
-  void AddService(VRServiceImpl* service,
-                  device::mojom::VRService::SetClientCallback callback);
+  void AddService(VRServiceImpl* service);
   void RemoveService(VRServiceImpl* service);
 
   device::VRDevice* GetDevice(unsigned int index);
@@ -55,6 +57,11 @@
 
  private:
   void InitializeProviders();
+  void OnProviderInitialized();
+  bool AreAllProvidersInitialized();
+
+  void AddDevice(device::VRDevice* device);
+  void RemoveDevice(device::VRDevice* device);
 
   ProviderList providers_;
 
@@ -62,7 +69,8 @@
   using DeviceMap = std::map<unsigned int, device::VRDevice*>;
   DeviceMap devices_;
 
-  bool vr_initialized_ = false;
+  bool providers_initialized_ = false;
+  size_t num_initialized_providers_ = 0;
 
   std::set<VRServiceImpl*> services_;
 
diff --git a/chrome/browser/vr/service/vr_device_manager_unittest.cc b/chrome/browser/vr/service/vr_device_manager_unittest.cc
index d9bd6b2..b23d04a 100644
--- a/chrome/browser/vr/service/vr_device_manager_unittest.cc
+++ b/chrome/browser/vr/service/vr_device_manager_unittest.cc
@@ -34,10 +34,14 @@
   }
 };
 
-class VRDisplayImplForTesting : public VRServiceImpl {
+class VRServiceImplForTesting : public VRServiceImpl {
  public:
-  VRDisplayImplForTesting() : VRServiceImpl() {}
-  ~VRDisplayImplForTesting() override = default;
+  VRServiceImplForTesting() : VRServiceImpl() {}
+  ~VRServiceImplForTesting() override = default;
+
+  int GetNumberOfConnectedDisplayHosts() {
+    return NumberOfConnectedDisplayHosts();
+  }
 };
 
 }  // namespace
@@ -60,10 +64,10 @@
 
   void TearDown() override { EXPECT_FALSE(VRDeviceManager::HasInstance()); }
 
-  std::unique_ptr<VRServiceImpl> BindService() {
+  std::unique_ptr<VRServiceImplForTesting> BindService() {
     device::mojom::VRServiceClientPtr proxy;
     device::FakeVRServiceClient client(mojo::MakeRequest(&proxy));
-    auto service = base::WrapUnique(new VRDisplayImplForTesting());
+    auto service = base::WrapUnique(new VRServiceImplForTesting());
     service->SetClient(std::move(proxy),
                        base::Bind(&VRDeviceManagerTest::onDisplaySynced,
                                   base::Unretained(this)));
@@ -90,7 +94,7 @@
 };
 
 TEST_F(VRDeviceManagerTest, InitializationTest) {
-  EXPECT_FALSE(Provider()->IsInitialized());
+  EXPECT_FALSE(Provider()->Initialized());
 
   // Calling GetDevices should initialize the service if it hasn't been
   // initialized yet or the providesr have been released.
@@ -98,15 +102,13 @@
   // initialization. And SetClient method in VRService class will invoke
   // GetVRDevices too.
   auto service = BindService();
-  DeviceManager()->AddService(service.get(), base::BindOnce([]() {}));
-  EXPECT_TRUE(Provider()->IsInitialized());
+  EXPECT_TRUE(Provider()->Initialized());
 }
 
 TEST_F(VRDeviceManagerTest, GetNoDevicesTest) {
   auto service = BindService();
-  DeviceManager()->AddService(service.get(), base::BindOnce([]() {}));
   // Calling GetVRDevices should initialize the providers.
-  EXPECT_TRUE(Provider()->IsInitialized());
+  EXPECT_TRUE(Provider()->Initialized());
 
   // GetDeviceByIndex should return nullptr if an invalid index in queried.
   device::VRDevice* queried_device = DeviceManager()->GetDevice(1);
@@ -143,4 +145,17 @@
   EXPECT_FALSE(VRDeviceManager::HasInstance());
 }
 
+// Ensure that devices added and removed are propagated to the service after
+// initialization.
+TEST_F(VRDeviceManagerTest, AddRemoveDevices) {
+  auto service = BindService();
+  EXPECT_EQ(1u, ServiceCount());
+  EXPECT_TRUE(Provider()->Initialized());
+  device::FakeVRDevice* device = new device::FakeVRDevice();
+  Provider()->AddDevice(base::WrapUnique(device));
+  EXPECT_EQ(1, service->GetNumberOfConnectedDisplayHosts());
+  Provider()->RemoveDevice(device->GetId());
+  EXPECT_EQ(0, service->GetNumberOfConnectedDisplayHosts());
+}
+
 }  // namespace vr
diff --git a/chrome/browser/vr/service/vr_service_impl.cc b/chrome/browser/vr/service/vr_service_impl.cc
index 31763d3..a528261 100644
--- a/chrome/browser/vr/service/vr_service_impl.cc
+++ b/chrome/browser/vr/service/vr_service_impl.cc
@@ -56,12 +56,18 @@
                               SetClientCallback callback) {
   DCHECK(!client_.get());
   client_ = std::move(service_client);
+  set_client_callback_ = std::move(callback);
 
   // Once a client has been connected AddService will force any VRDisplays to
   // send ConnectDevice to it so that it's populated with the currently active
   // displays. Thereafter it will stay up to date by virtue of listening for new
   // connected events.
-  VRDeviceManager::GetInstance()->AddService(this, std::move(callback));
+  VRDeviceManager::GetInstance()->AddService(this);
+}
+
+void VRServiceImpl::InitializationComplete() {
+  DCHECK(!set_client_callback_.is_null());
+  base::ResetAndReturn(&set_client_callback_).Run();
 }
 
 // Creates a VRDisplayImpl unique to this service so that the associated page
@@ -69,7 +75,7 @@
 void VRServiceImpl::ConnectDevice(device::VRDevice* device) {
   // Client should always be set as this is called through SetClient.
   DCHECK(client_);
-  DCHECK(displays_.count(device) == 0);
+  DCHECK(displays_.find(device) == displays_.end());
   device::mojom::VRDisplayInfoPtr display_info = device->GetVRDisplayInfo();
   DCHECK(display_info);
   if (!display_info)
@@ -78,6 +84,13 @@
       device, render_frame_host_, client_.get(), std::move(display_info));
 }
 
+void VRServiceImpl::RemoveDevice(device::VRDevice* device) {
+  DCHECK(client_);
+  auto it = displays_.find(device);
+  DCHECK(it != displays_.end());
+  displays_.erase(it);
+}
+
 void VRServiceImpl::SetListeningForActivate(bool listening) {
   for (const auto& display : displays_)
     display.second->SetListeningForActivate(listening);
diff --git a/chrome/browser/vr/service/vr_service_impl.h b/chrome/browser/vr/service/vr_service_impl.h
index ad88edf..dbe2e75a 100644
--- a/chrome/browser/vr/service/vr_service_impl.h
+++ b/chrome/browser/vr/service/vr_service_impl.h
@@ -38,13 +38,20 @@
   void SetClient(device::mojom::VRServiceClientPtr service_client,
                  SetClientCallback callback) override;
 
-  // Tells the render process that a new VR device is available.
+  // Tells the renderer that a new VR device is available.
   void ConnectDevice(device::VRDevice* device);
 
+  // Tells the renderer that a VR device has gone away.
+  void RemoveDevice(device::VRDevice* device);
+
+  void InitializationComplete();
+
  protected:
   // Constructor for tests.
   VRServiceImpl();
 
+  int NumberOfConnectedDisplayHosts() { return displays_.size(); }
+
  private:
   void SetBinding(mojo::StrongBindingPtr<VRService> binding);
 
@@ -59,6 +66,7 @@
   void OnWebContentsFocusChanged(content::RenderWidgetHost* host, bool focused);
 
   std::map<device::VRDevice*, std::unique_ptr<VRDisplayHost>> displays_;
+  SetClientCallback set_client_callback_;
   device::mojom::VRServiceClientPtr client_;
   content::RenderFrameHost* render_frame_host_;
   mojo::StrongBindingPtr<VRService> binding_;
diff --git a/device/vr/android/gvr/gvr_device_provider.cc b/device/vr/android/gvr/gvr_device_provider.cc
index 9cf4633..b979c4c 100644
--- a/device/vr/android/gvr/gvr_device_provider.cc
+++ b/device/vr/android/gvr/gvr_device_provider.cc
@@ -4,22 +4,26 @@
 
 #include "device/vr/android/gvr/gvr_device_provider.h"
 
-#include "device/vr/android/gvr/gvr_delegate_provider.h"
 #include "device/vr/android/gvr/gvr_device.h"
-#include "device/vr/vr_device.h"
 
 namespace device {
 
 GvrDeviceProvider::GvrDeviceProvider() = default;
 GvrDeviceProvider::~GvrDeviceProvider() = default;
 
-void GvrDeviceProvider::GetDevices(std::vector<VRDevice*>* devices) {
-  if (vr_device_.get())
-    devices->push_back(vr_device_.get());
+void GvrDeviceProvider::Initialize(
+    base::Callback<void(VRDevice*)> add_device_callback,
+    base::Callback<void(VRDevice*)> remove_device_callback,
+    base::OnceClosure initialization_complete) {
+  vr_device_ = GvrDevice::Create();
+  if (vr_device_)
+    add_device_callback.Run(vr_device_.get());
+  initialized_ = true;
+  std::move(initialization_complete).Run();
 }
 
-void GvrDeviceProvider::Initialize() {
-  vr_device_ = GvrDevice::Create();
+bool GvrDeviceProvider::Initialized() {
+  return initialized_;
 }
 
 }  // namespace device
diff --git a/device/vr/android/gvr/gvr_device_provider.h b/device/vr/android/gvr/gvr_device_provider.h
index 6bcc5dd..8bde258 100644
--- a/device/vr/android/gvr/gvr_device_provider.h
+++ b/device/vr/android/gvr/gvr_device_provider.h
@@ -13,7 +13,6 @@
 
 namespace device {
 
-class GvrDelegateProvider;
 class GvrDevice;
 
 class DEVICE_VR_EXPORT GvrDeviceProvider : public VRDeviceProvider {
@@ -21,12 +20,15 @@
   GvrDeviceProvider();
   ~GvrDeviceProvider() override;
 
-  void GetDevices(std::vector<VRDevice*>* devices) override;
-  void Initialize() override;
+  void Initialize(base::Callback<void(VRDevice*)> add_device_callback,
+                  base::Callback<void(VRDevice*)> remove_device_callback,
+                  base::OnceClosure initialization_complete) override;
+
+  bool Initialized() override;
 
  private:
-  void Initialize(device::GvrDelegateProvider* provider);
   std::unique_ptr<GvrDevice> vr_device_;
+  bool initialized_ = false;
 
   DISALLOW_COPY_AND_ASSIGN(GvrDeviceProvider);
 };
diff --git a/device/vr/openvr/openvr_device_provider.cc b/device/vr/openvr/openvr_device_provider.cc
index 8ba4aee..e1017c6 100644
--- a/device/vr/openvr/openvr_device_provider.cc
+++ b/device/vr/openvr/openvr_device_provider.cc
@@ -11,44 +11,44 @@
 
 namespace device {
 
-OpenVRDeviceProvider::OpenVRDeviceProvider()
-    : initialized_(false), vr_system_(nullptr) {}
+OpenVRDeviceProvider::OpenVRDeviceProvider() = default;
 
 OpenVRDeviceProvider::~OpenVRDeviceProvider() {
   device::GamepadDataFetcherManager::GetInstance()->RemoveSourceFactory(
       device::GAMEPAD_SOURCE_OPENVR);
-  device_ = nullptr;
   vr::VR_Shutdown();
 }
 
-void OpenVRDeviceProvider::GetDevices(std::vector<VRDevice*>* devices) {
-  if (initialized_) {
-    if (!device_) {
-      device_ = std::make_unique<OpenVRDevice>(vr_system_);
-      GamepadDataFetcherManager::GetInstance()->AddFactory(
-          new OpenVRGamepadDataFetcher::Factory(device_->GetId(), vr_system_));
-    }
-
-    if (device_) {
-      devices->push_back(device_.get());
-    }
-  }
+void OpenVRDeviceProvider::Initialize(
+    base::Callback<void(VRDevice*)> add_device_callback,
+    base::Callback<void(VRDevice*)> remove_device_callback,
+    base::OnceClosure initialization_complete) {
+  CreateDevice();
+  if (device_)
+    add_device_callback.Run(device_.get());
+  initialized_ = true;
+  std::move(initialization_complete).Run();
 }
 
-void OpenVRDeviceProvider::Initialize() {
-  if (!initialized_ && vr::VR_IsRuntimeInstalled() && vr::VR_IsHmdPresent()) {
-    vr::EVRInitError init_error = vr::VRInitError_None;
-    vr_system_ =
-        vr::VR_Init(&init_error, vr::EVRApplicationType::VRApplication_Scene);
+void OpenVRDeviceProvider::CreateDevice() {
+  if (!vr::VR_IsRuntimeInstalled() || !vr::VR_IsHmdPresent())
+    return;
 
-    if (init_error != vr::VRInitError_None) {
-      LOG(ERROR) << vr::VR_GetVRInitErrorAsEnglishDescription(init_error);
-      vr_system_ = nullptr;
-      return;
-    }
+  vr::EVRInitError init_error = vr::VRInitError_None;
+  vr::IVRSystem* vr_system =
+      vr::VR_Init(&init_error, vr::EVRApplicationType::VRApplication_Scene);
 
-    initialized_ = true;
+  if (init_error != vr::VRInitError_None) {
+    LOG(ERROR) << vr::VR_GetVRInitErrorAsEnglishDescription(init_error);
+    return;
   }
+  device_ = std::make_unique<OpenVRDevice>(vr_system);
+  GamepadDataFetcherManager::GetInstance()->AddFactory(
+      new OpenVRGamepadDataFetcher::Factory(device_->GetId(), vr_system));
+}
+
+bool OpenVRDeviceProvider::Initialized() {
+  return initialized_;
 }
 
 }  // namespace device
diff --git a/device/vr/openvr/openvr_device_provider.h b/device/vr/openvr/openvr_device_provider.h
index 4e5fa3fd..8483d1a 100644
--- a/device/vr/openvr/openvr_device_provider.h
+++ b/device/vr/openvr/openvr_device_provider.h
@@ -12,10 +12,6 @@
 #include "device/vr/vr_device_provider.h"
 #include "device/vr/vr_export.h"
 
-namespace vr {
-class IVRSystem;
-}  // namespace vr
-
 namespace device {
 
 class OpenVRDevice;
@@ -25,13 +21,17 @@
   OpenVRDeviceProvider();
   ~OpenVRDeviceProvider() override;
 
-  void GetDevices(std::vector<VRDevice*>* devices) override;
-  void Initialize() override;
+  void Initialize(base::Callback<void(VRDevice*)> add_device_callback,
+                  base::Callback<void(VRDevice*)> remove_device_callback,
+                  base::OnceClosure initialization_complete) override;
+
+  bool Initialized() override;
 
  private:
-  bool initialized_;
-  vr::IVRSystem* vr_system_;
+  void CreateDevice();
+
   std::unique_ptr<OpenVRDevice> device_;
+  bool initialized_ = false;
 
   DISALLOW_COPY_AND_ASSIGN(OpenVRDeviceProvider);
 };
diff --git a/device/vr/test/fake_vr_device_provider.cc b/device/vr/test/fake_vr_device_provider.cc
index 614848f..de96153 100644
--- a/device/vr/test/fake_vr_device_provider.cc
+++ b/device/vr/test/fake_vr_device_provider.cc
@@ -14,27 +14,36 @@
 
 void FakeVRDeviceProvider::AddDevice(std::unique_ptr<VRDevice> device) {
   devices_.push_back(std::move(device));
+  if (initialized_)
+    add_device_callback_.Run(devices_.back().get());
 }
 
-void FakeVRDeviceProvider::RemoveDevice(std::unique_ptr<VRDevice> device) {
-  std::vector<std::unique_ptr<VRDevice>>::iterator iter = devices_.begin();
-  while (iter != devices_.end()) {
-    if (device == *iter) {
-      iter = devices_.erase(iter);
-    } else {
-      ++iter;
-    }
+void FakeVRDeviceProvider::RemoveDevice(unsigned int device_id) {
+  auto it = std::find_if(devices_.begin(), devices_.end(),
+                         [device_id](const std::unique_ptr<VRDevice>& device) {
+                           return device->GetId() == device_id;
+                         });
+  if (initialized_)
+    remove_device_callback_.Run(it->get());
+  devices_.erase(it);
+}
+
+void FakeVRDeviceProvider::Initialize(
+    base::Callback<void(VRDevice*)> add_device_callback,
+    base::Callback<void(VRDevice*)> remove_device_callback,
+    base::OnceClosure initialization_complete) {
+  add_device_callback_ = std::move(add_device_callback);
+  remove_device_callback_ = std::move(remove_device_callback);
+
+  for (std::unique_ptr<VRDevice>& device : devices_) {
+    add_device_callback_.Run(device.get());
   }
-}
-
-void FakeVRDeviceProvider::GetDevices(std::vector<VRDevice*>* devices) {
-  for (const auto& device : devices_) {
-    devices->push_back(device.get());
-  }
-}
-
-void FakeVRDeviceProvider::Initialize() {
   initialized_ = true;
+  std::move(initialization_complete).Run();
+}
+
+bool FakeVRDeviceProvider::Initialized() {
+  return initialized_;
 }
 
 }  // namespace device
diff --git a/device/vr/test/fake_vr_device_provider.h b/device/vr/test/fake_vr_device_provider.h
index 1956ea5..1efda093 100644
--- a/device/vr/test/fake_vr_device_provider.h
+++ b/device/vr/test/fake_vr_device_provider.h
@@ -22,15 +22,18 @@
   // Adds devices to the provider with the given device, which will be
   // returned when GetDevices is queried.
   void AddDevice(std::unique_ptr<VRDevice> device);
-  void RemoveDevice(std::unique_ptr<VRDevice> device);
-  bool IsInitialized() { return initialized_; }
+  void RemoveDevice(unsigned int device_id);
 
-  void GetDevices(std::vector<VRDevice*>* devices) override;
-  void Initialize() override;
+  void Initialize(base::Callback<void(VRDevice*)> add_device_callback,
+                  base::Callback<void(VRDevice*)> remove_device_callback,
+                  base::OnceClosure initialization_complete) override;
+  bool Initialized() override;
 
  private:
   std::vector<std::unique_ptr<VRDevice>> devices_;
   bool initialized_;
+  base::Callback<void(VRDevice*)> add_device_callback_;
+  base::Callback<void(VRDevice*)> remove_device_callback_;
 
   DISALLOW_COPY_AND_ASSIGN(FakeVRDeviceProvider);
 };
diff --git a/device/vr/vr_device_provider.h b/device/vr/vr_device_provider.h
index a81ed42..8bf86944 100644
--- a/device/vr/vr_device_provider.h
+++ b/device/vr/vr_device_provider.h
@@ -7,6 +7,8 @@
 
 #include <vector>
 
+#include "base/callback.h"
+
 namespace device {
 
 class VRDevice;
@@ -16,10 +18,14 @@
   VRDeviceProvider() {}
   virtual ~VRDeviceProvider() {}
 
-  virtual void GetDevices(std::vector<VRDevice*>* devices) = 0;
-
   // If the VR API requires initialization that should happen here.
-  virtual void Initialize() = 0;
+  virtual void Initialize(
+      base::Callback<void(VRDevice*)> add_device_callback,
+      base::Callback<void(VRDevice*)> remove_device_callback,
+      base::OnceClosure initialization_complete) = 0;
+
+  // Returns true if initialization is complete.
+  virtual bool Initialized() = 0;
 };
 
 }  // namespace device