Bug 1299937 - Part 6: Handle Stop vibrating when the window defoucses; r=qdot
authorDaosheng Mu <daoshengmu@gmail.com>
Tue, 07 Mar 2017 10:17:57 +0800
changeset 349320 5d8e162ef5f73106037a6ad5c34770f26ab86447
parent 349319 3c1984bdf4047df79fde8e84264f17de80351f20
child 349321 78c1934f6a77ce1e94cbd035a8f01e570466ba82
push id39455
push userdmu@mozilla.com
push dateFri, 24 Mar 2017 03:25:06 +0000
treeherderautoland@5d8e162ef5f7 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersqdot
bugs1299937
milestone55.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1299937 - Part 6: Handle Stop vibrating when the window defoucses; r=qdot MozReview-Commit-ID: Kvd40jnSPvK
dom/base/nsGlobalWindow.cpp
dom/base/nsGlobalWindow.h
dom/gamepad/GamepadManager.cpp
dom/gamepad/GamepadManager.h
dom/gamepad/ipc/GamepadEventChannelParent.cpp
dom/gamepad/ipc/GamepadEventChannelParent.h
dom/gamepad/ipc/PGamepadEventChannel.ipdl
dom/tests/mochitest/gamepad/test_gamepad_extensions.html
gfx/vr/VRManager.cpp
gfx/vr/VRManager.h
gfx/vr/gfxVROpenVR.cpp
gfx/vr/gfxVROpenVR.h
gfx/vr/ipc/PVRManager.ipdl
gfx/vr/ipc/VRManagerChild.cpp
gfx/vr/ipc/VRManagerParent.cpp
gfx/vr/ipc/VRManagerParent.h
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -10498,31 +10498,32 @@ nsGlobalWindow::IsTopLevelWindowActive()
 
 void nsGlobalWindow::SetIsBackground(bool aIsBackground)
 {
   MOZ_ASSERT(IsOuterWindow());
 
   bool resetTimers = (!aIsBackground && AsOuter()->IsBackground());
   nsPIDOMWindow::SetIsBackground(aIsBackground);
 
+  nsGlobalWindow* inner = GetCurrentInnerWindowInternal();
+
   if (aIsBackground) {
     MOZ_ASSERT(!resetTimers);
-    return;
-  }
-
-  nsGlobalWindow* inner = GetCurrentInnerWindowInternal();
-  if (!inner) {
-    return;
-  }
-
-  if (resetTimers) {
-    inner->mTimeoutManager->ResetTimersForThrottleReduction();
-  }
-
-  inner->SyncGamepadState();
+    // Notify gamepadManager we are at the background window,
+    // we need to stop vibrate.
+    if (inner) {
+      inner->StopGamepadHaptics();
+    }
+    return;
+  } else if (inner) {
+    if (resetTimers) {
+      inner->mTimeoutManager->ResetTimersForThrottleReduction();
+    }
+    inner->SyncGamepadState();
+  }
 }
 
 void nsGlobalWindow::MaybeUpdateTouchState()
 {
   FORWARD_TO_INNER_VOID(MaybeUpdateTouchState, ());
 
   if (mMayHaveTouchEventListener) {
     nsCOMPtr<nsIObserverService> observerService =
@@ -13596,16 +13597,26 @@ nsGlobalWindow::SyncGamepadState()
   if (mHasSeenGamepadInput) {
     RefPtr<GamepadManager> gamepadManager(GamepadManager::GetService());
     for (auto iter = mGamepads.Iter(); !iter.Done(); iter.Next()) {
       gamepadManager->SyncGamepadState(iter.Key(), iter.UserData());
     }
   }
 }
 
+void
+nsGlobalWindow::StopGamepadHaptics()
+{
+  MOZ_ASSERT(IsInnerWindow());
+  if (mHasSeenGamepadInput) {
+    RefPtr<GamepadManager> gamepadManager(GamepadManager::GetService());
+    gamepadManager->StopHaptics();
+  }
+}
+
 bool
 nsGlobalWindow::UpdateVRDisplays(nsTArray<RefPtr<mozilla::dom::VRDisplay>>& aDevices)
 {
   FORWARD_TO_INNER(UpdateVRDisplays, (aDevices), false);
 
   VRDisplay::UpdateVRDisplays(mVRDisplays, AsInner());
   aDevices = mVRDisplays;
   return true;
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -744,16 +744,17 @@ public:
   // Inner windows only.
   void AddGamepad(uint32_t aIndex, mozilla::dom::Gamepad* aGamepad);
   void RemoveGamepad(uint32_t aIndex);
   void GetGamepads(nsTArray<RefPtr<mozilla::dom::Gamepad> >& aGamepads);
   already_AddRefed<mozilla::dom::Gamepad> GetGamepad(uint32_t aIndex);
   void SetHasSeenGamepadInput(bool aHasSeen);
   bool HasSeenGamepadInput();
   void SyncGamepadState();
+  void StopGamepadHaptics();
 
   // Inner windows only.
   // Enable/disable updates for gamepad input.
   void EnableGamepadUpdates();
   void DisableGamepadUpdates();
 
   // Inner windows only.
   // Enable/disable updates for VR
--- a/dom/gamepad/GamepadManager.cpp
+++ b/dom/gamepad/GamepadManager.cpp
@@ -693,16 +693,32 @@ GamepadManager::VibrateHaptic(uint32_t a
                                       mPromiseID);
     }
   }
 
   ++mPromiseID;
   return promise.forget();
 }
 
+void
+GamepadManager::StopHaptics()
+{
+  for (auto iter = mGamepads.Iter(); !iter.Done(); iter.Next()) {
+    const uint32_t gamepadIndex = iter.UserData()->HashKey();
+    if (gamepadIndex >= VR_GAMEPAD_IDX_OFFSET) {
+      const uint32_t index = gamepadIndex - VR_GAMEPAD_IDX_OFFSET;
+      mVRChannelChild->SendStopVibrateHaptic(index);
+    } else {
+      for (auto& channelChild : mChannelChildren) {
+        channelChild->SendStopVibrateHaptic(gamepadIndex);
+      }
+    }
+  }
+}
+
 //Override nsIIPCBackgroundChildCreateCallback
 void
 GamepadManager::ActorCreated(PBackgroundChild *aActor)
 {
   MOZ_ASSERT(aActor);
   GamepadEventChannelChild *child = new GamepadEventChannelChild();
   PGamepadEventChannelChild *initedChild =
     aActor->SendPGamepadEventChannelConstructor(child);
--- a/dom/gamepad/GamepadManager.h
+++ b/dom/gamepad/GamepadManager.h
@@ -82,17 +82,19 @@ class GamepadManager final : public nsIO
   already_AddRefed<Gamepad> GetGamepad(uint32_t aIndex) const;
 
   // Receive GamepadChangeEvent messages from parent process to fire DOM events
   void Update(const GamepadChangeEvent& aGamepadEvent);
 
   // Trigger vibrate haptic event to gamepad channels.
   already_AddRefed<Promise> VibrateHaptic(uint32_t aControllerIdx, uint32_t aHapticIndex,
                                           double aIntensity, double aDuration,
-                                          nsIGlobalObject* aGlobal);
+                                          nsIGlobalObject* aGlobal, ErrorResult& aRv);
+  // Send stop haptic events to gamepad channels.
+  void StopHaptics();
 
  protected:
   GamepadManager();
   ~GamepadManager() {};
 
   // Fire a gamepadconnected or gamepaddisconnected event for the gamepad
   // at |aIndex| to all windows that are listening and have received
   // gamepad input.
--- a/dom/gamepad/ipc/GamepadEventChannelParent.cpp
+++ b/dom/gamepad/ipc/GamepadEventChannelParent.cpp
@@ -84,16 +84,23 @@ GamepadEventChannelParent::RecvVibrateHa
 
   if (SendReplyGamepadVibrateHaptic(aPromiseID)) {
     return IPC_OK();
   }
 
   return IPC_FAIL(this, "SendReplyGamepadVibrateHaptic fail.");
 }
 
+mozilla::ipc::IPCResult
+GamepadEventChannelParent::RecvStopVibrateHaptic(const uint32_t& aGamepadIndex)
+{
+  // TODO: Bug 680289, implement for standard gamepads
+  return IPC_OK();
+}
+
 void
 GamepadEventChannelParent::ActorDestroy(ActorDestroyReason aWhy)
 {
   AssertIsOnBackgroundThread();
 
   // It may be called because IPDL child side crashed, we'll
   // not receive RecvGamepadListenerRemoved in that case
   if (mHasGamepadListener) {
--- a/dom/gamepad/ipc/GamepadEventChannelParent.h
+++ b/dom/gamepad/ipc/GamepadEventChannelParent.h
@@ -17,16 +17,18 @@ class GamepadEventChannelParent final : 
   virtual void ActorDestroy(ActorDestroyReason aWhy) override;
   virtual mozilla::ipc::IPCResult RecvGamepadListenerAdded() override;
   virtual mozilla::ipc::IPCResult RecvGamepadListenerRemoved() override;
   virtual mozilla::ipc::IPCResult RecvVibrateHaptic(const uint32_t& aControllerIdx,
                                                     const uint32_t& aHapticIndex,
                                                     const double& aIntensity,
                                                     const double& aDuration,
                                                     const uint32_t& aPromiseID) override;
+  virtual mozilla::ipc::IPCResult RecvStopVibrateHaptic(
+                                    const uint32_t& aGamepadIndex) override;
   void DispatchUpdateEvent(const GamepadChangeEvent& aEvent);
   bool HasGamepadListener() const { return mHasGamepadListener; }
  private:
   ~GamepadEventChannelParent() {}
   bool mHasGamepadListener;
   nsCOMPtr<nsIThread> mBackgroundThread;
 };
 
--- a/dom/gamepad/ipc/PGamepadEventChannel.ipdl
+++ b/dom/gamepad/ipc/PGamepadEventChannel.ipdl
@@ -9,16 +9,18 @@ namespace dom {
 
 async protocol PGamepadEventChannel {
   manager PBackground;
   parent:
     async GamepadListenerAdded();
     async GamepadListenerRemoved();
     async VibrateHaptic(uint32_t aControllerIdx, uint32_t aHapticIndex,
                         double aIntensity, double aDuration, uint32_t aPromiseID);
+    async StopVibrateHaptic(uint32_t aGamepadIndex);
+
   child:
     async __delete__();
     async GamepadUpdate(GamepadChangeEvent aGamepadEvent);
     async ReplyGamepadVibrateHaptic(uint32_t aPromiseID);
 };
 
 }
 }
--- a/dom/tests/mochitest/gamepad/test_gamepad_extensions.html
+++ b/dom/tests/mochitest/gamepad/test_gamepad_extensions.html
@@ -32,18 +32,16 @@ window.addEventListener("gamepadbuttondo
   SpecialPowers.executeSoon(tests[testNum++]);
 });
 
 function pressButton() {
   GamepadService.newButtonEvent(gamepad_index, 0, true);
   GamepadService.newButtonEvent(gamepad_index, 0, false);
 }
 
-runGamepadTest(startTest);
-
 function startTest() {
   SpecialPowers.pushPrefEnv({ "set": [["dom.gamepad.extensions.enabled", true]] });
   // Add a gamepad
   GamepadService.addGamepad("test gamepad", // id
                      GamepadService.standardMapping,
                      GamepadService.leftHand,
                      4,
                      2,
@@ -104,22 +102,33 @@ function posecheck() {
      "correct gamepadPose angularAcceleration");
   is(checkValueInFloat32Array(pose.linearVelocity, poseLinVel), true,
      "correct gamepadPose linearVelocity");
   is(checkValueInFloat32Array(pose.linearAcceleration, poseLinAcc), true,
      "correct gamepadPose linearAcceleration");
   pressButton();
 }
 
+function setFrameVisible(f, visible) {
+  var Ci = SpecialPowers.Ci;
+  var docshell = SpecialPowers.wrap(f.contentWindow).QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIWebNavigation).QueryInterface(Ci.nsIDocShell);
+  docshell.isActive = visible;
+}
+
 function haptictest() {
   var gamepads = navigator.getGamepads();
   var hapticActuators = gamepads[0].hapticActuators[0];
   hapticActuators.pulse(1, 100).then(function(result) {
     is(result, true, "gamepad hapticActuators test success.");
     GamepadService.removeGamepad(gamepad_index);
     SimpleTest.finish();
   });
+  // When page is background, we should stop our haptics and still
+  // can get the promise.
+  var f1 = document.getElementById('f1');
+  setFrameVisible(f1, false);
 }
 
 </script>
+<iframe id="f1" src="gamepad_frame_state.html" onload="runGamepadTest(startTest)"></iframe>
 </body>
 </html>
 
--- a/gfx/vr/VRManager.cpp
+++ b/gfx/vr/VRManager.cpp
@@ -429,10 +429,26 @@ VRManager::VibrateHaptic(uint32_t aContr
 
 {
   for (uint32_t i = 0; i < mManagers.Length(); ++i) {
     mManagers[i]->VibrateHaptic(aControllerIdx, aHapticIndex,
                                 aIntensity, aDuration, aPromiseID);
   }
 }
 
+void
+VRManager::StopVibrateHaptic(uint32_t aControllerIdx)
+{
+  for (const auto& manager: mManagers) {
+    manager->StopVibrateHaptic(aControllerIdx);
+  }
+}
+
+void
+VRManager::NotifyVibrateHapticCompleted(uint32_t aPromiseID)
+{
+  for (auto iter = mVRManagerParents.Iter(); !iter.Done(); iter.Next()) {
+    Unused << iter.Get()->GetKey()->SendReplyGamepadVibrateHaptic(aPromiseID);
+  }
+}
+
 } // namespace gfx
 } // namespace mozilla
--- a/gfx/vr/VRManager.h
+++ b/gfx/vr/VRManager.h
@@ -46,16 +46,18 @@ public:
   void SubmitFrame(VRLayerParent* aLayer, layers::PTextureParent* aTexture,
                    const gfx::Rect& aLeftEyeRect,
                    const gfx::Rect& aRightEyeRect);
   RefPtr<gfx::VRControllerHost> GetController(const uint32_t& aControllerID);
   void GetVRControllerInfo(nsTArray<VRControllerInfo>& aControllerInfo);
   void CreateVRTestSystem();
   void VibrateHaptic(uint32_t aControllerIdx, uint32_t aHapticIndex,
                      double aIntensity, double aDuration, uint32_t aPromiseID);
+  void StopVibrateHaptic(uint32_t aControllerIdx);
+  void NotifyVibrateHapticCompleted(uint32_t aPromiseID);
 
 protected:
   VRManager();
   ~VRManager();
 
 private:
   RefPtr<layers::TextureHost> mLastFrame;
 
--- a/gfx/vr/gfxVROpenVR.cpp
+++ b/gfx/vr/gfxVROpenVR.cpp
@@ -390,17 +390,17 @@ VRDisplayOpenVR::NotifyVSync()
   PollEvents();
 }
 
 VRControllerOpenVR::VRControllerOpenVR(dom::GamepadHand aHand, uint32_t aNumButtons,
                                        uint32_t aNumAxes)
   : VRControllerHost(VRDeviceType::OpenVR)
   , mTrigger(0)
   , mVibrateThread(nullptr)
-  , mIsVibrating(false)
+  , mIsVibrateStopped(false)
 {
   MOZ_COUNT_CTOR_INHERITED(VRControllerOpenVR, VRControllerHost);
   mControllerInfo.mControllerName.AssignLiteral("OpenVR Gamepad");
   mControllerInfo.mMappingType = GamepadMappingType::_empty;
   mControllerInfo.mHand = aHand;
   mControllerInfo.mNumButtons = aNumButtons;
   mControllerInfo.mNumAxes = aNumAxes;
   mControllerInfo.mNumHaptics = kNumOpenVRHaptcs;
@@ -445,18 +445,25 @@ VRControllerOpenVR::UpdateVibrateHaptic(
                                         uint32_t aHapticIndex,
                                         double aIntensity,
                                         double aDuration,
                                         uint64_t aVibrateIndex,
                                         uint32_t aPromiseID)
 {
   // UpdateVibrateHaptic() only can be called by mVibrateThread
   MOZ_ASSERT(mVibrateThread == NS_GetCurrentThread());
+
+  // It has been interrupted by loss focus.
+  if (mIsVibrateStopped) {
+    VibrateHapticComplete(aPromiseID);
+    return;
+  }
   // Avoid the previous vibrate event to override the new one.
   if (mVibrateIndex != aVibrateIndex) {
+    VibrateHapticComplete(aPromiseID);
     return;
   }
 
   double duration = (aIntensity == 0) ? 0 : aDuration;
   // We expect OpenVR to vibrate for 5 ms, but we found it only response the
   // commend ~ 3.9 ms. For duration time longer than 3.9 ms, we separate them
   // to a loop of 3.9 ms for make users feel that is a continuous events.
   uint32_t microSec = (duration < 3.9 ? duration : 3.9) * 1000 * aIntensity;
@@ -469,49 +476,62 @@ VRControllerOpenVR::UpdateVibrateHaptic(
   if (duration >= kVibrateRate) {
     MOZ_ASSERT(mVibrateThread);
 
     RefPtr<Runnable> runnable =
       NewRunnableMethod<vr::IVRSystem*, uint32_t, double, double, uint64_t, uint32_t>
         (this, &VRControllerOpenVR::UpdateVibrateHaptic, aVRSystem,
          aHapticIndex, aIntensity, duration - kVibrateRate, aVibrateIndex, aPromiseID);
     NS_DelayedDispatchToCurrentThread(runnable.forget(), kVibrateRate);
+  } else {
+    // The pulse has completed
+    VibrateHapticComplete(aPromiseID);
   }
 }
 
 void
+VRControllerOpenVR::VibrateHapticComplete(uint32_t aPromiseID)
+{
+  VRManager *vm = VRManager::Get();
+  MOZ_ASSERT(vm);
+
+  CompositorThreadHolder::Loop()->PostTask(NewRunnableMethod<uint32_t>
+    (vm, &VRManager::NotifyVibrateHapticCompleted, aPromiseID));
+}
+
+void
 VRControllerOpenVR::VibrateHaptic(vr::IVRSystem* aVRSystem,
                                   uint32_t aHapticIndex,
                                   double aIntensity,
                                   double aDuration,
                                   uint32_t aPromiseID)
 {
   // Spinning up the haptics thread at the first haptics call.
   if (!mVibrateThread) {
     nsresult rv = NS_NewThread(getter_AddRefs(mVibrateThread));
     MOZ_ASSERT(mVibrateThread);
 
     if (NS_FAILED(rv)) {
       MOZ_ASSERT(false, "Failed to create async thread.");
     }
   }
   ++mVibrateIndex;
+  mIsVibrateStopped = false;
 
-  mIsVibrating = true;
   RefPtr<Runnable> runnable =
       NewRunnableMethod<vr::IVRSystem*, uint32_t, double, double, uint64_t, uint32_t>
         (this, &VRControllerOpenVR::UpdateVibrateHaptic, aVRSystem,
          aHapticIndex, aIntensity, aDuration, mVibrateIndex, aPromiseID);
   mVibrateThread->Dispatch(runnable.forget(), NS_DISPATCH_NORMAL);
 }
 
 void
 VRControllerOpenVR::StopVibrateHaptic()
 {
-  mIsVibrating = false;
+  mIsVibrateStopped = true;
 }
 
 VRSystemManagerOpenVR::VRSystemManagerOpenVR()
   : mVRSystem(nullptr)
   , mOpenVRInstalled(false)
 {
 }
 
--- a/gfx/vr/gfxVROpenVR.h
+++ b/gfx/vr/gfxVROpenVR.h
@@ -89,22 +89,23 @@ protected:
 
 private:
   void UpdateVibrateHaptic(vr::IVRSystem* aVRSystem,
                            uint32_t aHapticIndex,
                            double aIntensity,
                            double aDuration,
                            uint64_t aVibrateIndex,
                            uint32_t aPromiseID);
+  void VibrateHapticComplete(uint32_t aPromiseID);
 
   // The index of tracked devices from vr::IVRSystem.
   uint32_t mTrackedIndex;
   float mTrigger;
   nsCOMPtr<nsIThread> mVibrateThread;
-  bool mIsVibrating;
+  Atomic<bool> mIsVibrateStopped;
 };
 
 } // namespace impl
 
 class VRSystemManagerOpenVR : public VRSystemManager
 {
 public:
   static already_AddRefed<VRSystemManagerOpenVR> Create();
--- a/gfx/vr/ipc/PVRManager.ipdl
+++ b/gfx/vr/ipc/PVRManager.ipdl
@@ -51,16 +51,17 @@ parent:
 
   sync GetSensorState(uint32_t aDisplayID) returns(VRHMDSensorState aState);
   async SetHaveEventListener(bool aHaveEventListener);
 
   async ControllerListenerAdded();
   async ControllerListenerRemoved();
   async VibrateHaptic(uint32_t aControllerIdx, uint32_t aHapticIndex,
                       double aIntensity, double aDuration, uint32_t aPromiseID);
+  async StopVibrateHaptic(uint32_t aControllerIdx);
 
   async CreateVRTestSystem();
   async CreateVRServiceTestDisplay(nsCString aID, uint32_t aPromiseID);
   async CreateVRServiceTestController(nsCString aID, uint32_t aPromiseID);
   async SetDisplayInfoToMockDisplay(uint32_t aDeviceID, VRDisplayInfo aDisplayInfo);
   async SetSensorStateToMockDisplay(uint32_t aDeviceID, VRHMDSensorState aSensorState);
 
   async NewButtonEventToMockController(uint32_t aDeviceID, long aButton,
--- a/gfx/vr/ipc/VRManagerChild.cpp
+++ b/gfx/vr/ipc/VRManagerChild.cpp
@@ -682,16 +682,21 @@ VRManagerChild::AddPromise(const uint32_
 {
   MOZ_ASSERT(!mGamepadPromiseList.Get(aID, nullptr));
   mGamepadPromiseList.Put(aID, aPromise);
 }
 
 mozilla::ipc::IPCResult
 VRManagerChild::RecvReplyGamepadVibrateHaptic(const uint32_t& aPromiseID)
 {
+  // VRManagerChild could be at other processes, but GamepadManager
+  // only exists at the content process or the same process
+  // in non-e10s mode.
+  MOZ_ASSERT(XRE_IsContentProcess() || IsSameProcess());
+
   RefPtr<dom::Promise> p;
   if (!mGamepadPromiseList.Get(aPromiseID, getter_AddRefs(p))) {
     MOZ_CRASH("We should always have a promise.");
   }
 
   p->MaybeResolve(true);
   mGamepadPromiseList.Remove(aPromiseID);
   return IPC_OK();
--- a/gfx/vr/ipc/VRManagerParent.cpp
+++ b/gfx/vr/ipc/VRManagerParent.cpp
@@ -446,23 +446,44 @@ VRManagerParent::RecvVibrateHaptic(const
                                    const uint32_t& aPromiseID)
 {
   VRManager* vm = VRManager::Get();
   vm->VibrateHaptic(aControllerIdx, aHapticIndex, aIntensity,
                     aDuration, aPromiseID);
   return IPC_OK();
 }
 
+mozilla::ipc::IPCResult
+VRManagerParent::RecvStopVibrateHaptic(const uint32_t& aControllerIdx)
+{
+  VRManager* vm = VRManager::Get();
+  vm->StopVibrateHaptic(aControllerIdx);
+  return IPC_OK();
+}
+
 bool
 VRManagerParent::SendGamepadUpdate(const GamepadChangeEvent& aGamepadEvent)
 {
   // GamepadManager only exists at the content process
   // or the same process in non-e10s mode.
   if (mHaveControllerListener &&
       (mIsContentChild || IsSameProcess())) {
     return PVRManagerParent::SendGamepadUpdate(aGamepadEvent);
   } else {
     return true;
   }
 }
 
+bool
+VRManagerParent::SendReplyGamepadVibrateHaptic(const uint32_t& aPromiseID)
+{
+  // GamepadManager only exists at the content process
+  // or the same process in non-e10s mode.
+  if (mHaveControllerListener &&
+      (mIsContentChild || IsSameProcess())) {
+    return PVRManagerParent::SendReplyGamepadVibrateHaptic(aPromiseID);
+  } else {
+    return true;
+  }
+}
+
 } // namespace gfx
 } // namespace mozilla
--- a/gfx/vr/ipc/VRManagerParent.h
+++ b/gfx/vr/ipc/VRManagerParent.h
@@ -56,16 +56,17 @@ public:
 
   virtual bool IsSameProcess() const override;
   bool HaveEventListener();
   bool HaveControllerListener();
 
   virtual void NotifyNotUsed(PTextureParent* aTexture, uint64_t aTransactionId) override;
   virtual void SendAsyncMessage(const InfallibleTArray<AsyncParentMessageData>& aMessage) override;
   bool SendGamepadUpdate(const GamepadChangeEvent& aGamepadEvent);
+  bool SendReplyGamepadVibrateHaptic(const uint32_t& aPromiseID);
 
 protected:
   ~VRManagerParent();
 
   virtual PTextureParent* AllocPTextureParent(const SurfaceDescriptor& aSharedData,
                                               const LayersBackend& aLayersBackend,
                                               const TextureFlags& aFlags,
                                               const uint64_t& aSerial) override;
@@ -88,16 +89,17 @@ protected:
   virtual mozilla::ipc::IPCResult RecvRefreshDisplays() override;
   virtual mozilla::ipc::IPCResult RecvResetSensor(const uint32_t& aDisplayID) override;
   virtual mozilla::ipc::IPCResult RecvGetSensorState(const uint32_t& aDisplayID, VRHMDSensorState* aState) override;
   virtual mozilla::ipc::IPCResult RecvSetHaveEventListener(const bool& aHaveEventListener) override;
   virtual mozilla::ipc::IPCResult RecvControllerListenerAdded() override;
   virtual mozilla::ipc::IPCResult RecvControllerListenerRemoved() override;
   virtual mozilla::ipc::IPCResult RecvVibrateHaptic(const uint32_t& aControllerIdx, const uint32_t& aHapticIndex,
                                                     const double& aIntensity, const double& aDuration, const uint32_t& aPromiseID) override;
+  virtual mozilla::ipc::IPCResult RecvStopVibrateHaptic(const uint32_t& aControllerIdx) override;
   
   virtual mozilla::ipc::IPCResult RecvCreateVRTestSystem() override;
   virtual mozilla::ipc::IPCResult RecvCreateVRServiceTestDisplay(const nsCString& aID, const uint32_t& aPromiseID) override;
   virtual mozilla::ipc::IPCResult RecvCreateVRServiceTestController(const nsCString& aID, const uint32_t& aPromiseID) override;
   virtual mozilla::ipc::IPCResult RecvSetDisplayInfoToMockDisplay(const uint32_t& aDeviceID,
                                                                   const VRDisplayInfo& aDisplayInfo) override;
   virtual mozilla::ipc::IPCResult RecvSetSensorStateToMockDisplay(const uint32_t& aDeviceID,
                                                                   const VRHMDSensorState& aSensorState) override;