mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-28 07:13:20 +00:00
Bug 1732410 wait for focus before proceeding for enumerateDevices() Promises r=jib,nika
https://github.com/w3c/mediacapture-main/pull/574 Focus on browser chrome widgets is accepted provided the tab is fully active and foreground. https://github.com/w3c/mediacapture-main/issues/752#issuecomment-742036800 Differential Revision: https://phabricator.services.mozilla.com/D127051
This commit is contained in:
parent
a88ced1c73
commit
e91d1ff3ec
@ -33,6 +33,7 @@
|
||||
#include "mozilla/dom/HTMLIFrameElement.h"
|
||||
#include "mozilla/dom/Location.h"
|
||||
#include "mozilla/dom/LocationBinding.h"
|
||||
#include "mozilla/dom/MediaDevices.h"
|
||||
#include "mozilla/dom/PopupBlocker.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "mozilla/dom/SessionStorageManager.h"
|
||||
@ -2930,14 +2931,19 @@ void BrowsingContext::DidSet(FieldIndex<IDX_IsActiveBrowserWindowInternal>,
|
||||
if (RefPtr<Document> doc = aContext->GetExtantDocument()) {
|
||||
doc->UpdateDocumentStates(NS_DOCUMENT_STATE_WINDOW_INACTIVE, true);
|
||||
|
||||
RefPtr<nsPIDOMWindowInner> win = doc->GetInnerWindow();
|
||||
RefPtr<MediaDevices> devices;
|
||||
if (isActivateEvent && (devices = win->GetExtantMediaDevices())) {
|
||||
devices->BrowserWindowBecameActive();
|
||||
}
|
||||
|
||||
if (XRE_IsContentProcess() &&
|
||||
(!aContext->GetParent() || !aContext->GetParent()->IsInProcess())) {
|
||||
// Send the inner window an activate/deactivate event if
|
||||
// the context is the top of a sub-tree of in-process
|
||||
// contexts.
|
||||
nsContentUtils::DispatchEventOnlyToChrome(
|
||||
doc, doc->GetWindow()->GetCurrentInnerWindow(),
|
||||
isActivateEvent ? u"activate"_ns : u"deactivate"_ns,
|
||||
doc, win, isActivateEvent ? u"activate"_ns : u"deactivate"_ns,
|
||||
CanBubble::eYes, Cancelable::eYes, nullptr);
|
||||
}
|
||||
}
|
||||
|
@ -178,6 +178,7 @@ class Navigator final : public nsISupports, public nsWrapperCache {
|
||||
already_AddRefed<LegacyMozTCPSocket> MozTCPSocket();
|
||||
network::Connection* GetConnection(ErrorResult& aRv);
|
||||
MediaDevices* GetMediaDevices(ErrorResult& aRv);
|
||||
MediaDevices* GetExtantMediaDevices() const { return mMediaDevices; };
|
||||
|
||||
void GetGamepads(nsTArray<RefPtr<Gamepad>>& aGamepads, ErrorResult& aRv);
|
||||
GamepadServiceTest* RequestGamepadServiceTest();
|
||||
|
@ -137,6 +137,7 @@
|
||||
#include "mozilla/dom/LocalStorage.h"
|
||||
#include "mozilla/dom/LocalStorageCommon.h"
|
||||
#include "mozilla/dom/Location.h"
|
||||
#include "mozilla/dom/MediaDevices.h"
|
||||
#include "mozilla/dom/MediaKeys.h"
|
||||
#include "mozilla/dom/NavigatorBinding.h"
|
||||
#include "mozilla/dom/Nullable.h"
|
||||
@ -2310,6 +2311,10 @@ Navigator* nsPIDOMWindowInner::Navigator() {
|
||||
return mNavigator;
|
||||
}
|
||||
|
||||
MediaDevices* nsPIDOMWindowInner::GetExtantMediaDevices() const {
|
||||
return mNavigator ? mNavigator->GetExtantMediaDevices() : nullptr;
|
||||
}
|
||||
|
||||
VisualViewport* nsGlobalWindowInner::VisualViewport() {
|
||||
if (!mVisualViewport) {
|
||||
mVisualViewport = new mozilla::dom::VisualViewport(this);
|
||||
@ -5570,6 +5575,10 @@ void nsGlobalWindowInner::Resume(bool aIncludeSubWindows) {
|
||||
mAudioContexts[i]->ResumeFromChrome();
|
||||
}
|
||||
|
||||
if (RefPtr<MediaDevices> devices = GetExtantMediaDevices()) {
|
||||
devices->WindowResumed();
|
||||
}
|
||||
|
||||
mTimeoutManager->Resume();
|
||||
|
||||
ResumeIdleRequests();
|
||||
@ -5721,6 +5730,13 @@ void nsGlobalWindowInner::SyncStateFromParentWindow() {
|
||||
}
|
||||
}
|
||||
|
||||
void nsGlobalWindowInner::UpdateBackgroundState() {
|
||||
if (RefPtr<MediaDevices> devices = GetExtantMediaDevices()) {
|
||||
devices->BackgroundStateChanged();
|
||||
}
|
||||
mTimeoutManager->UpdateBackgroundState();
|
||||
}
|
||||
|
||||
template <typename Method, typename... Args>
|
||||
CallState nsGlobalWindowInner::CallOnInProcessDescendantsInternal(
|
||||
BrowsingContext* aBrowsingContext, bool aChildOnly, Method aMethod,
|
||||
|
@ -325,6 +325,12 @@ class nsGlobalWindowInner final : public mozilla::dom::EventTarget,
|
||||
virtual bool IsFrozen() const override;
|
||||
void SyncStateFromParentWindow();
|
||||
|
||||
// Called on the current inner window of a browsing context when its
|
||||
// background state changes according to selected tab or visibility of the
|
||||
// browser window. Used with Suspend()/Resume() or Freeze()/Thaw() because
|
||||
// background state may change while the inner window is not current.
|
||||
void UpdateBackgroundState();
|
||||
|
||||
mozilla::dom::DebuggerNotificationManager*
|
||||
GetOrCreateDebuggerNotificationManager() override;
|
||||
|
||||
|
@ -6757,7 +6757,7 @@ void nsGlobalWindowOuter::SetIsBackground(bool aIsBackground) {
|
||||
nsGlobalWindowInner* inner = GetCurrentInnerWindowInternal();
|
||||
|
||||
if (inner && changed) {
|
||||
inner->mTimeoutManager->UpdateBackgroundState();
|
||||
inner->UpdateBackgroundState();
|
||||
}
|
||||
|
||||
if (aIsBackground) {
|
||||
|
@ -62,6 +62,7 @@ class DocGroup;
|
||||
class Document;
|
||||
class Element;
|
||||
class Location;
|
||||
class MediaDevices;
|
||||
class MediaKeys;
|
||||
class Navigator;
|
||||
class Performance;
|
||||
@ -577,6 +578,7 @@ class nsPIDOMWindowInner : public mozIDOMWindow {
|
||||
uint32_t GetMarkedCCGeneration() { return mMarkedCCGeneration; }
|
||||
|
||||
mozilla::dom::Navigator* Navigator();
|
||||
mozilla::dom::MediaDevices* GetExtantMediaDevices() const;
|
||||
virtual mozilla::dom::Location* Location() = 0;
|
||||
|
||||
virtual nsresult GetControllers(nsIControllers** aControllers) = 0;
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "mozilla/dom/MediaDevices.h"
|
||||
|
||||
#include "AudioDeviceInfo.h"
|
||||
#include "mozilla/dom/BrowsingContext.h"
|
||||
#include "mozilla/dom/Document.h"
|
||||
#include "mozilla/dom/MediaStreamBinding.h"
|
||||
#include "mozilla/dom/MediaDeviceInfo.h"
|
||||
@ -139,10 +140,39 @@ already_AddRefed<Promise> MediaDevices::EnumerateDevices(ErrorResult& aRv) {
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
mPendingEnumerateDevicesPromises.AppendElement(p);
|
||||
MaybeResumeDeviceExposure();
|
||||
return p.forget();
|
||||
}
|
||||
|
||||
void MediaDevices::MaybeResumeDeviceExposure() {
|
||||
if (mPendingEnumerateDevicesPromises.IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
nsPIDOMWindowInner* window = GetOwner();
|
||||
if (!window || !window->IsFullyActive()) {
|
||||
return;
|
||||
}
|
||||
BrowsingContext* bc = window->GetBrowsingContext();
|
||||
if (!bc->IsActive() || // not foreground tab
|
||||
!bc->GetIsActiveBrowserWindow()) { // browser window does not have focus
|
||||
return;
|
||||
}
|
||||
|
||||
auto pending = std::move(mPendingEnumerateDevicesPromises);
|
||||
for (auto& promise : pending) {
|
||||
ResumeEnumerateDevices(std::move(promise));
|
||||
}
|
||||
}
|
||||
|
||||
void MediaDevices::ResumeEnumerateDevices(RefPtr<Promise> aPromise) {
|
||||
nsCOMPtr<nsPIDOMWindowInner> window = GetOwner();
|
||||
MOZ_ASSERT(window, "Fully active document should have window");
|
||||
RefPtr<MediaDevices> self(this);
|
||||
MediaManager::Get()->EnumerateDevices(owner)->Then(
|
||||
MediaManager::Get()->EnumerateDevices(window)->Then(
|
||||
GetCurrentSerialEventTarget(), __func__,
|
||||
[this, self, p](RefPtr<MediaManager::MediaDeviceSetRefCnt>&& aDevices) {
|
||||
[this, self,
|
||||
aPromise](RefPtr<MediaManager::MediaDeviceSetRefCnt>&& aDevices) {
|
||||
nsPIDOMWindowInner* window = GetWindowIfCurrent();
|
||||
if (!window) {
|
||||
return; // Leave Promise pending after navigation by design.
|
||||
@ -189,16 +219,15 @@ already_AddRefed<Promise> MediaDevices::EnumerateDevices(ErrorResult& aRv) {
|
||||
infos.AppendElement(MakeRefPtr<MediaDeviceInfo>(
|
||||
device->mID, device->mKind, label, device->mGroupID));
|
||||
}
|
||||
p->MaybeResolve(std::move(infos));
|
||||
aPromise->MaybeResolve(std::move(infos));
|
||||
},
|
||||
[this, self, p](const RefPtr<MediaMgrError>& error) {
|
||||
[this, self, aPromise](const RefPtr<MediaMgrError>& error) {
|
||||
nsPIDOMWindowInner* window = GetWindowIfCurrent();
|
||||
if (!window) {
|
||||
return; // Leave Promise pending after navigation by design.
|
||||
}
|
||||
error->Reject(p);
|
||||
error->Reject(aPromise);
|
||||
});
|
||||
return p.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<Promise> MediaDevices::GetDisplayMedia(
|
||||
@ -479,7 +508,10 @@ RefPtr<MediaDevices::SinkInfoPromise> MediaDevices::GetSinkDevice(
|
||||
});
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED0(MediaDevices, DOMEventTargetHelper)
|
||||
NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED_0(MediaDevices,
|
||||
DOMEventTargetHelper)
|
||||
NS_IMPL_CYCLE_COLLECTION_INHERITED(MediaDevices, DOMEventTargetHelper,
|
||||
mPendingEnumerateDevicesPromises)
|
||||
|
||||
void MediaDevices::OnDeviceChange() {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
@ -39,6 +39,7 @@ class MediaDevices final : public DOMEventTargetHelper {
|
||||
explicit MediaDevices(nsPIDOMWindowInner* aWindow);
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(MediaDevices, DOMEventTargetHelper)
|
||||
|
||||
JSObject* WrapObject(JSContext* cx,
|
||||
JS::Handle<JSObject*> aGivenProto) override;
|
||||
@ -79,14 +80,21 @@ class MediaDevices final : public DOMEventTargetHelper {
|
||||
void EventListenerAdded(nsAtom* aType) override;
|
||||
using DOMEventTargetHelper::EventListenerAdded;
|
||||
|
||||
void BackgroundStateChanged() { MaybeResumeDeviceExposure(); }
|
||||
void WindowResumed() { MaybeResumeDeviceExposure(); }
|
||||
void BrowserWindowBecameActive() { MaybeResumeDeviceExposure(); }
|
||||
|
||||
private:
|
||||
class GumResolver;
|
||||
class EnumDevResolver;
|
||||
class GumRejecter;
|
||||
|
||||
virtual ~MediaDevices();
|
||||
void MaybeResumeDeviceExposure();
|
||||
void ResumeEnumerateDevices(RefPtr<Promise> aPromise);
|
||||
|
||||
nsTHashSet<nsString> mExplicitlyGrantedAudioOutputIds;
|
||||
nsTArray<RefPtr<Promise>> mPendingEnumerateDevicesPromises;
|
||||
nsCOMPtr<nsITimer> mFuzzTimer;
|
||||
|
||||
// Connect/Disconnect on main thread only
|
||||
|
@ -1,4 +0,0 @@
|
||||
[enumerateDevices-with-navigation.https.html]
|
||||
expected: TIMEOUT
|
||||
[enumerateDevices with navigation]
|
||||
expected: TIMEOUT
|
@ -1,5 +1,3 @@
|
||||
[enumerateDevices-in-background.https.html]
|
||||
disabled:
|
||||
if buildapp != 'browser': uses Firefox-for-Desktop specific API
|
||||
[enumerateDevices in background]
|
||||
expected: FAIL
|
||||
|
@ -1,3 +0,0 @@
|
||||
[enumerateDevices-without-focus.https.html]
|
||||
[enumerateDevices without focus]
|
||||
expected: FAIL
|
Loading…
Reference in New Issue
Block a user