forked from mirrors/gecko-dev
Bug 1589554 - Part 2: Implement Screen Wake Lock API. r=dom-core,edgar
Depends on D189508 Differential Revision: https://phabricator.services.mozilla.com/D189509
This commit is contained in:
parent
0c8b54eb5e
commit
248841bc9c
9 changed files with 351 additions and 12 deletions
|
|
@ -233,6 +233,7 @@
|
||||||
#include "mozilla/dom/URL.h"
|
#include "mozilla/dom/URL.h"
|
||||||
#include "mozilla/dom/UseCounterMetrics.h"
|
#include "mozilla/dom/UseCounterMetrics.h"
|
||||||
#include "mozilla/dom/UserActivation.h"
|
#include "mozilla/dom/UserActivation.h"
|
||||||
|
#include "mozilla/dom/WakeLockJS.h"
|
||||||
#include "mozilla/dom/WakeLockSentinel.h"
|
#include "mozilla/dom/WakeLockSentinel.h"
|
||||||
#include "mozilla/dom/WindowBinding.h"
|
#include "mozilla/dom/WindowBinding.h"
|
||||||
#include "mozilla/dom/WindowContext.h"
|
#include "mozilla/dom/WindowContext.h"
|
||||||
|
|
@ -18260,6 +18261,44 @@ nsTHashSet<RefPtr<WakeLockSentinel>>& Document::ActiveWakeLocks(
|
||||||
return mActiveLocks.LookupOrInsert(aType);
|
return mActiveLocks.LookupOrInsert(aType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class UnlockAllWakeLockRunnable final : public Runnable {
|
||||||
|
public:
|
||||||
|
UnlockAllWakeLockRunnable(WakeLockType aType, Document* aDoc)
|
||||||
|
: Runnable("UnlockAllWakeLocks"), mType(aType), mDoc(aDoc) {}
|
||||||
|
|
||||||
|
// MOZ_CAN_RUN_SCRIPT_BOUNDARY until Runnable::Run is MOZ_CAN_RUN_SCRIPT. See
|
||||||
|
// bug 1535398.
|
||||||
|
MOZ_CAN_RUN_SCRIPT_BOUNDARY
|
||||||
|
NS_IMETHOD Run() override {
|
||||||
|
// Move, as ReleaseWakeLock will try to remove from and possibly allow
|
||||||
|
// scripts via onrelease to add to document.[[ActiveLocks]]["screen"]
|
||||||
|
nsCOMPtr<Document> doc = mDoc;
|
||||||
|
nsTHashSet<RefPtr<WakeLockSentinel>> locks =
|
||||||
|
std::move(doc->ActiveWakeLocks(mType));
|
||||||
|
for (const auto& lock : locks) {
|
||||||
|
// ReleaseWakeLock runs script, which could release other locks
|
||||||
|
if (!lock->Released()) {
|
||||||
|
ReleaseWakeLock(doc, MOZ_KnownLive(lock), mType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
~UnlockAllWakeLockRunnable() = default;
|
||||||
|
|
||||||
|
private:
|
||||||
|
WakeLockType mType;
|
||||||
|
nsCOMPtr<Document> mDoc;
|
||||||
|
};
|
||||||
|
|
||||||
|
void Document::UnlockAllWakeLocks(WakeLockType aType) {
|
||||||
|
// Perform unlock in a runnable to prevent UnlockAll being MOZ_CAN_RUN_SCRIPT
|
||||||
|
RefPtr<UnlockAllWakeLockRunnable> runnable =
|
||||||
|
MakeRefPtr<UnlockAllWakeLockRunnable>(aType, this);
|
||||||
|
NS_DispatchToMainThread(runnable);
|
||||||
|
}
|
||||||
|
|
||||||
RefPtr<Document::AutomaticStorageAccessPermissionGrantPromise>
|
RefPtr<Document::AutomaticStorageAccessPermissionGrantPromise>
|
||||||
Document::AutomaticStorageAccessPermissionCanBeGranted(bool hasUserActivation) {
|
Document::AutomaticStorageAccessPermissionCanBeGranted(bool hasUserActivation) {
|
||||||
// requestStorageAccessForOrigin may not require user activation. If we don't
|
// requestStorageAccessForOrigin may not require user activation. If we don't
|
||||||
|
|
|
||||||
|
|
@ -3540,6 +3540,8 @@ class Document : public nsINode,
|
||||||
|
|
||||||
nsTHashSet<RefPtr<WakeLockSentinel>>& ActiveWakeLocks(WakeLockType aType);
|
nsTHashSet<RefPtr<WakeLockSentinel>>& ActiveWakeLocks(WakeLockType aType);
|
||||||
|
|
||||||
|
void UnlockAllWakeLocks(WakeLockType aType);
|
||||||
|
|
||||||
// ParentNode
|
// ParentNode
|
||||||
nsIHTMLCollection* Children();
|
nsIHTMLCollection* Children();
|
||||||
uint32_t ChildElementCount();
|
uint32_t ChildElementCount();
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,85 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#include "ErrorList.h"
|
||||||
|
#include "mozilla/Assertions.h"
|
||||||
|
#include "mozilla/dom/Document.h"
|
||||||
|
#include "mozilla/dom/Event.h"
|
||||||
|
#include "mozilla/dom/FeaturePolicyUtils.h"
|
||||||
|
#include "mozilla/dom/Navigator.h"
|
||||||
|
#include "mozilla/dom/Promise.h"
|
||||||
|
#include "mozilla/dom/WakeLockBinding.h"
|
||||||
|
#include "mozilla/Hal.h"
|
||||||
|
#include "nsCOMPtr.h"
|
||||||
|
#include "nsError.h"
|
||||||
|
#include "nsIGlobalObject.h"
|
||||||
|
#include "nsISupports.h"
|
||||||
#include "nsPIDOMWindow.h"
|
#include "nsPIDOMWindow.h"
|
||||||
#include "WakeLockJS.h"
|
#include "WakeLockJS.h"
|
||||||
|
#include "WakeLockSentinel.h"
|
||||||
|
|
||||||
namespace mozilla::dom {
|
namespace mozilla::dom {
|
||||||
|
|
||||||
|
nsLiteralCString WakeLockJS::GetRequestErrorMessage(RequestError aRv) {
|
||||||
|
switch (aRv) {
|
||||||
|
case RequestError::DocInactive:
|
||||||
|
return "The requesting document is inactive."_ns;
|
||||||
|
case RequestError::DocHidden:
|
||||||
|
return "The requesting document is hidden."_ns;
|
||||||
|
case RequestError::PolicyDisallowed:
|
||||||
|
return "A permissions policy does not allow screen-wake-lock for the requesting document."_ns;
|
||||||
|
case RequestError::PrefDisabled:
|
||||||
|
return "The pref dom.screenwakelock.enabled is disabled."_ns;
|
||||||
|
case RequestError::InternalFailure:
|
||||||
|
return "A browser-internal error occured."_ns;
|
||||||
|
default:
|
||||||
|
MOZ_ASSERT_UNREACHABLE("Unknown error reason");
|
||||||
|
return "Unknown error"_ns;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://w3c.github.io/screen-wake-lock/#the-request-method steps 2-5
|
||||||
|
WakeLockJS::RequestError WakeLockJS::WakeLockAllowedForDocument(
|
||||||
|
Document* aDoc) {
|
||||||
|
if (!aDoc) {
|
||||||
|
return RequestError::InternalFailure;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 2. check policy-controlled feature screen-wake-lock
|
||||||
|
if (!FeaturePolicyUtils::IsFeatureAllowed(aDoc, u"screen-wake-lock"_ns)) {
|
||||||
|
return RequestError::PolicyDisallowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 4 check doc active
|
||||||
|
if (!aDoc->IsActive()) {
|
||||||
|
return RequestError::DocInactive;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 5. check doc visible
|
||||||
|
if (aDoc->Hidden()) {
|
||||||
|
return RequestError::DocHidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
return RequestError::Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://w3c.github.io/screen-wake-lock/#dfn-applicable-wake-lock
|
||||||
|
static bool IsWakeLockApplicable(WakeLockType aType) {
|
||||||
|
// only currently supported wake lock type
|
||||||
|
return aType == WakeLockType::Screen;
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://w3c.github.io/screen-wake-lock/#dfn-release-a-wake-lock
|
||||||
|
void ReleaseWakeLock(Document* aDoc, WakeLockSentinel* aLock,
|
||||||
|
WakeLockType aType) {
|
||||||
|
MOZ_ASSERT(aLock);
|
||||||
|
MOZ_ASSERT(aDoc);
|
||||||
|
|
||||||
|
RefPtr<WakeLockSentinel> kungFuDeathGrip = aLock;
|
||||||
|
aDoc->ActiveWakeLocks(aType).Remove(aLock);
|
||||||
|
aLock->NotifyLockReleased();
|
||||||
|
}
|
||||||
|
|
||||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WakeLockJS, mWindow)
|
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WakeLockJS, mWindow)
|
||||||
|
|
||||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(WakeLockJS)
|
NS_IMPL_CYCLE_COLLECTING_ADDREF(WakeLockJS)
|
||||||
|
|
@ -20,7 +94,11 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WakeLockJS)
|
||||||
NS_INTERFACE_MAP_ENTRY(nsIDocumentActivity)
|
NS_INTERFACE_MAP_ENTRY(nsIDocumentActivity)
|
||||||
NS_INTERFACE_MAP_END
|
NS_INTERFACE_MAP_END
|
||||||
|
|
||||||
WakeLockJS::WakeLockJS(nsPIDOMWindowInner* aWindow) : mWindow(aWindow) {}
|
WakeLockJS::WakeLockJS(nsPIDOMWindowInner* aWindow) : mWindow(aWindow) {
|
||||||
|
AttachListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
WakeLockJS::~WakeLockJS() { DetachListeners(); }
|
||||||
|
|
||||||
nsISupports* WakeLockJS::GetParentObject() const { return mWindow; }
|
nsISupports* WakeLockJS::GetParentObject() const { return mWindow; }
|
||||||
|
|
||||||
|
|
@ -29,12 +107,102 @@ JSObject* WakeLockJS::WrapObject(JSContext* aCx,
|
||||||
return WakeLock_Binding::Wrap(aCx, this, aGivenProto);
|
return WakeLock_Binding::Wrap(aCx, this, aGivenProto);
|
||||||
}
|
}
|
||||||
|
|
||||||
already_AddRefed<Promise> WakeLockJS::Request(WakeLockType aType) {
|
// https://w3c.github.io/screen-wake-lock/#the-request-method Step 7.3
|
||||||
return nullptr;
|
Result<already_AddRefed<WakeLockSentinel>, WakeLockJS::RequestError>
|
||||||
|
WakeLockJS::Obtain(WakeLockType aType) {
|
||||||
|
// Step 7.3.1. check visibility again
|
||||||
|
nsCOMPtr<Document> doc = mWindow->GetExtantDoc();
|
||||||
|
if (!doc) {
|
||||||
|
return Err(RequestError::InternalFailure);
|
||||||
|
}
|
||||||
|
if (doc->Hidden()) {
|
||||||
|
return Err(RequestError::DocHidden);
|
||||||
|
}
|
||||||
|
// Step 7.3.3. let lock be a new WakeLockSentinel
|
||||||
|
RefPtr<WakeLockSentinel> lock =
|
||||||
|
MakeRefPtr<WakeLockSentinel>(mWindow->AsGlobal(), aType);
|
||||||
|
// Step 7.3.2. acquire a wake lock
|
||||||
|
if (IsWakeLockApplicable(aType)) {
|
||||||
|
lock->AcquireActualLock();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Steps 7.3.4., 7.3.5. Append lock to locks and resolve promise with lock
|
||||||
|
doc->ActiveWakeLocks(aType).Insert(lock);
|
||||||
|
|
||||||
|
return lock.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WakeLockJS::NotifyOwnerDocumentActivityChanged() {}
|
// https://w3c.github.io/screen-wake-lock/#the-request-method
|
||||||
|
already_AddRefed<Promise> WakeLockJS::Request(WakeLockType aType,
|
||||||
|
ErrorResult& aRv) {
|
||||||
|
nsCOMPtr<nsIGlobalObject> global = mWindow->AsGlobal();
|
||||||
|
|
||||||
NS_IMETHODIMP WakeLockJS::HandleEvent(Event* aEvent) { return NS_OK; }
|
RefPtr<Promise> promise = Promise::Create(global, aRv);
|
||||||
|
NS_ENSURE_FALSE(aRv.Failed(), nullptr);
|
||||||
|
|
||||||
|
// Steps 1-5
|
||||||
|
nsCOMPtr<Document> doc = mWindow->GetExtantDoc();
|
||||||
|
RequestError rv = WakeLockAllowedForDocument(doc);
|
||||||
|
if (rv != RequestError::Success) {
|
||||||
|
promise->MaybeRejectWithNotAllowedError(GetRequestErrorMessage(rv));
|
||||||
|
return promise.forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 7.1. Requesting permission to use screen-wake-lock
|
||||||
|
// Note: implemented in a future part, for now always try to obtain
|
||||||
|
auto lockOrErr = Obtain(aType);
|
||||||
|
if (lockOrErr.isOk()) {
|
||||||
|
RefPtr<WakeLockSentinel> lock = lockOrErr.unwrap();
|
||||||
|
promise->MaybeResolve(lock);
|
||||||
|
} else {
|
||||||
|
promise->MaybeRejectWithNotAllowedError(
|
||||||
|
GetRequestErrorMessage(lockOrErr.unwrapErr()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return promise.forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WakeLockJS::AttachListeners() {
|
||||||
|
nsCOMPtr<Document> doc = mWindow->GetExtantDoc();
|
||||||
|
MOZ_ASSERT(doc);
|
||||||
|
DebugOnly<nsresult> rv =
|
||||||
|
doc->AddSystemEventListener(u"visibilitychange"_ns, this, true, false);
|
||||||
|
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||||
|
doc->RegisterActivityObserver(ToSupports(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
void WakeLockJS::DetachListeners() {
|
||||||
|
if (mWindow) {
|
||||||
|
if (nsCOMPtr<Document> doc = mWindow->GetExtantDoc()) {
|
||||||
|
doc->RemoveSystemEventListener(u"visibilitychange"_ns, this, true);
|
||||||
|
|
||||||
|
doc->UnregisterActivityObserver(ToSupports(this));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WakeLockJS::NotifyOwnerDocumentActivityChanged() {
|
||||||
|
nsCOMPtr<Document> doc = mWindow->GetExtantDoc();
|
||||||
|
MOZ_ASSERT(doc);
|
||||||
|
if (!doc->IsActive()) {
|
||||||
|
doc->UnlockAllWakeLocks(WakeLockType::Screen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP WakeLockJS::HandleEvent(Event* aEvent) {
|
||||||
|
nsAutoString type;
|
||||||
|
aEvent->GetType(type);
|
||||||
|
|
||||||
|
if (type.EqualsLiteral("visibilitychange")) {
|
||||||
|
nsCOMPtr<Document> doc = do_QueryInterface(aEvent->GetTarget());
|
||||||
|
NS_ENSURE_STATE(doc);
|
||||||
|
|
||||||
|
if (doc->Hidden()) {
|
||||||
|
doc->UnlockAllWakeLocks(WakeLockType::Screen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace mozilla::dom
|
} // namespace mozilla::dom
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
#define DOM_WAKELOCKJS_H_
|
#define DOM_WAKELOCKJS_H_
|
||||||
|
|
||||||
#include "js/TypeDecls.h"
|
#include "js/TypeDecls.h"
|
||||||
|
#include "mozilla/Attributes.h"
|
||||||
#include "mozilla/dom/WakeLockBinding.h"
|
#include "mozilla/dom/WakeLockBinding.h"
|
||||||
#include "nsIDOMEventListener.h"
|
#include "nsIDOMEventListener.h"
|
||||||
#include "nsIDocumentActivity.h"
|
#include "nsIDocumentActivity.h"
|
||||||
|
|
@ -26,6 +27,15 @@ class WakeLockSentinel;
|
||||||
|
|
||||||
namespace mozilla::dom {
|
namespace mozilla::dom {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Management class for wake locks held from client scripts.
|
||||||
|
* Instances of this class have two purposes:
|
||||||
|
* - Implement navigator.wakeLock.request which creates a WakeLockSentinel
|
||||||
|
* - Listen for state changes that require all WakeLockSentinel to be released
|
||||||
|
* The WakeLockSentinel objects are held in document.mActiveLocks.
|
||||||
|
*
|
||||||
|
* https://www.w3.org/TR/screen-wake-lock/#the-wakelock-interface
|
||||||
|
*/
|
||||||
class WakeLockJS final : public nsIDOMEventListener,
|
class WakeLockJS final : public nsIDOMEventListener,
|
||||||
public nsWrapperCache,
|
public nsWrapperCache,
|
||||||
public nsIDocumentActivity {
|
public nsIDocumentActivity {
|
||||||
|
|
@ -41,7 +51,7 @@ class WakeLockJS final : public nsIDOMEventListener,
|
||||||
explicit WakeLockJS(nsPIDOMWindowInner* aWindow);
|
explicit WakeLockJS(nsPIDOMWindowInner* aWindow);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
~WakeLockJS() = default;
|
~WakeLockJS();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
nsISupports* GetParentObject() const;
|
nsISupports* GetParentObject() const;
|
||||||
|
|
@ -49,12 +59,37 @@ class WakeLockJS final : public nsIDOMEventListener,
|
||||||
JSObject* WrapObject(JSContext* aCx,
|
JSObject* WrapObject(JSContext* aCx,
|
||||||
JS::Handle<JSObject*> aGivenProto) override;
|
JS::Handle<JSObject*> aGivenProto) override;
|
||||||
|
|
||||||
already_AddRefed<Promise> Request(WakeLockType aType);
|
already_AddRefed<Promise> Request(WakeLockType aType, ErrorResult& aRv);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
enum class RequestError {
|
||||||
|
Success,
|
||||||
|
DocInactive,
|
||||||
|
DocHidden,
|
||||||
|
PolicyDisallowed,
|
||||||
|
PrefDisabled,
|
||||||
|
InternalFailure
|
||||||
|
};
|
||||||
|
|
||||||
|
static nsLiteralCString GetRequestErrorMessage(RequestError aRv);
|
||||||
|
|
||||||
|
static RequestError WakeLockAllowedForDocument(Document* aDoc);
|
||||||
|
|
||||||
|
void AttachListeners();
|
||||||
|
void DetachListeners();
|
||||||
|
|
||||||
|
Result<already_AddRefed<WakeLockSentinel>, RequestError> Obtain(
|
||||||
|
WakeLockType aType);
|
||||||
|
|
||||||
|
void UnlockAll(WakeLockType aType);
|
||||||
|
|
||||||
RefPtr<nsPIDOMWindowInner> mWindow;
|
RefPtr<nsPIDOMWindowInner> mWindow;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
MOZ_CAN_RUN_SCRIPT
|
||||||
|
void ReleaseWakeLock(Document* aDoc, WakeLockSentinel* aLock,
|
||||||
|
WakeLockType aType);
|
||||||
|
|
||||||
} // namespace mozilla::dom
|
} // namespace mozilla::dom
|
||||||
|
|
||||||
#endif // DOM_WAKELOCKJS_H_
|
#endif // DOM_WAKELOCKJS_H_
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,14 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#include "mozilla/Assertions.h"
|
||||||
|
#include "mozilla/dom/Document.h"
|
||||||
|
#include "mozilla/dom/Event.h"
|
||||||
|
#include "mozilla/dom/EventBinding.h"
|
||||||
|
#include "mozilla/dom/Promise.h"
|
||||||
#include "mozilla/dom/WakeLockSentinelBinding.h"
|
#include "mozilla/dom/WakeLockSentinelBinding.h"
|
||||||
|
#include "mozilla/Hal.h"
|
||||||
|
#include "WakeLockJS.h"
|
||||||
#include "WakeLockSentinel.h"
|
#include "WakeLockSentinel.h"
|
||||||
|
|
||||||
namespace mozilla::dom {
|
namespace mozilla::dom {
|
||||||
|
|
@ -14,8 +21,67 @@ JSObject* WakeLockSentinel::WrapObject(JSContext* cx,
|
||||||
return WakeLockSentinel_Binding::Wrap(cx, this, aGivenProto);
|
return WakeLockSentinel_Binding::Wrap(cx, this, aGivenProto);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WakeLockSentinel::Released() const { return false; }
|
bool WakeLockSentinel::Released() const { return mReleased; }
|
||||||
|
|
||||||
already_AddRefed<Promise> WakeLockSentinel::ReleaseLock() { return nullptr; }
|
void WakeLockSentinel::NotifyLockReleased() {
|
||||||
|
MOZ_ASSERT(!mReleased);
|
||||||
|
mReleased = true;
|
||||||
|
|
||||||
|
if (mHoldsActualLock) {
|
||||||
|
MOZ_ASSERT(mType == WakeLockType::Screen);
|
||||||
|
NS_DispatchToMainThread(NS_NewRunnableFunction("ReleaseWakeLock", []() {
|
||||||
|
hal::ModifyWakeLock(u"screen"_ns, hal::WAKE_LOCK_REMOVE_ONE,
|
||||||
|
hal::WAKE_LOCK_NO_CHANGE);
|
||||||
|
}));
|
||||||
|
mHoldsActualLock = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
EventInit init;
|
||||||
|
init.mBubbles = false;
|
||||||
|
init.mCancelable = false;
|
||||||
|
RefPtr<Event> event = Event::Constructor(this, u"release"_ns, init);
|
||||||
|
DispatchTrustedEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WakeLockSentinel::AcquireActualLock() {
|
||||||
|
MOZ_ASSERT(mType == WakeLockType::Screen);
|
||||||
|
MOZ_ASSERT(!mHoldsActualLock);
|
||||||
|
mHoldsActualLock = true;
|
||||||
|
NS_DispatchToMainThread(NS_NewRunnableFunction("AcquireWakeLock", []() {
|
||||||
|
hal::ModifyWakeLock(u"screen"_ns, hal::WAKE_LOCK_ADD_ONE,
|
||||||
|
hal::WAKE_LOCK_NO_CHANGE);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://w3c.github.io/screen-wake-lock/#the-release-method
|
||||||
|
already_AddRefed<Promise> WakeLockSentinel::ReleaseLock(ErrorResult& aRv) {
|
||||||
|
// ReleaseWakeLock will remove this from document.[[ActiveLocks]]
|
||||||
|
RefPtr<WakeLockSentinel> kungFuDeathGrip(this);
|
||||||
|
|
||||||
|
if (!mReleased) {
|
||||||
|
nsCOMPtr<nsIGlobalObject> global = GetOwnerGlobal();
|
||||||
|
if (!global) {
|
||||||
|
aRv.Throw(NS_ERROR_NULL_POINTER);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
nsCOMPtr<nsPIDOMWindowInner> window = global->GetAsInnerWindow();
|
||||||
|
if (!window) {
|
||||||
|
aRv.Throw(NS_ERROR_NULL_POINTER);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
nsCOMPtr<Document> doc = window->GetExtantDoc();
|
||||||
|
if (!doc) {
|
||||||
|
aRv.Throw(NS_ERROR_NULL_POINTER);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
ReleaseWakeLock(doc, this, mType);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RefPtr<Promise> p =
|
||||||
|
Promise::CreateResolvedWithUndefined(GetOwnerGlobal(), aRv)) {
|
||||||
|
return p.forget();
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace mozilla::dom
|
} // namespace mozilla::dom
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
#define DOM_WAKELOCKSENTINEL_H_
|
#define DOM_WAKELOCKSENTINEL_H_
|
||||||
|
|
||||||
#include "js/TypeDecls.h"
|
#include "js/TypeDecls.h"
|
||||||
|
#include "mozilla/Attributes.h"
|
||||||
#include "mozilla/DOMEventTargetHelper.h"
|
#include "mozilla/DOMEventTargetHelper.h"
|
||||||
#include "mozilla/dom/WakeLockBinding.h"
|
#include "mozilla/dom/WakeLockBinding.h"
|
||||||
|
|
||||||
|
|
@ -25,7 +26,10 @@ class WakeLockSentinel final : public DOMEventTargetHelper {
|
||||||
: DOMEventTargetHelper(aOwnerWindow), mType(aType) {}
|
: DOMEventTargetHelper(aOwnerWindow), mType(aType) {}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
~WakeLockSentinel() = default;
|
~WakeLockSentinel() {
|
||||||
|
MOZ_DIAGNOSTIC_ASSERT(mReleased);
|
||||||
|
MOZ_DIAGNOSTIC_ASSERT(!mHoldsActualLock);
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
JSObject* WrapObject(JSContext* aCx,
|
JSObject* WrapObject(JSContext* aCx,
|
||||||
|
|
@ -36,12 +40,35 @@ class WakeLockSentinel final : public DOMEventTargetHelper {
|
||||||
WakeLockType Type() const { return mType; }
|
WakeLockType Type() const { return mType; }
|
||||||
|
|
||||||
MOZ_CAN_RUN_SCRIPT
|
MOZ_CAN_RUN_SCRIPT
|
||||||
already_AddRefed<Promise> ReleaseLock();
|
already_AddRefed<Promise> ReleaseLock(ErrorResult& aRv);
|
||||||
|
|
||||||
|
MOZ_CAN_RUN_SCRIPT
|
||||||
|
void NotifyLockReleased();
|
||||||
|
|
||||||
IMPL_EVENT_HANDLER(release);
|
IMPL_EVENT_HANDLER(release);
|
||||||
|
|
||||||
|
// Acquire underlying system wake lock by modifying the HAL wake lock counter
|
||||||
|
void AcquireActualLock();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
WakeLockType mType;
|
WakeLockType mType;
|
||||||
|
|
||||||
|
bool mReleased = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* To avoid user fingerprinting, WakeLockJS::Request will provide a
|
||||||
|
* WakeLockSentinel even if the lock type is not applicable or cannot be
|
||||||
|
* obtained.
|
||||||
|
* But when releasing this sentinel, we have to know whether
|
||||||
|
* AcquireActualLock was called.
|
||||||
|
*
|
||||||
|
* https://w3c.github.io/screen-wake-lock/#dfn-applicable-wake-lock
|
||||||
|
* https://w3c.github.io/screen-wake-lock/#the-request-method
|
||||||
|
*/
|
||||||
|
bool mHoldsActualLock = false;
|
||||||
|
|
||||||
|
// Time when this object was created / the wake lock acquired.
|
||||||
|
TimeStamp mAcquireTime;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace mozilla::dom
|
} // namespace mozilla::dom
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@ static FeatureMap sSupportedFeatures[] = {
|
||||||
FeaturePolicyUtils::FeaturePolicyValue::eSelf},
|
FeaturePolicyUtils::FeaturePolicyValue::eSelf},
|
||||||
{"speaker-selection", FeaturePolicyUtils::FeaturePolicyValue::eSelf},
|
{"speaker-selection", FeaturePolicyUtils::FeaturePolicyValue::eSelf},
|
||||||
{"storage-access", FeaturePolicyUtils::FeaturePolicyValue::eAll},
|
{"storage-access", FeaturePolicyUtils::FeaturePolicyValue::eAll},
|
||||||
|
{"screen-wake-lock", FeaturePolicyUtils::FeaturePolicyValue::eSelf},
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
[SecureContext, Exposed=(Window)]
|
[SecureContext, Exposed=(Window)]
|
||||||
interface WakeLock {
|
interface WakeLock {
|
||||||
|
[Throws]
|
||||||
Promise<WakeLockSentinel> request(optional WakeLockType type = "screen");
|
Promise<WakeLockSentinel> request(optional WakeLockType type = "screen");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
interface WakeLockSentinel : EventTarget {
|
interface WakeLockSentinel : EventTarget {
|
||||||
readonly attribute boolean released;
|
readonly attribute boolean released;
|
||||||
readonly attribute WakeLockType type;
|
readonly attribute WakeLockType type;
|
||||||
[BinaryName="releaseLock"]
|
[BinaryName="releaseLock", Throws]
|
||||||
Promise<undefined> release();
|
Promise<undefined> release();
|
||||||
attribute EventHandler onrelease;
|
attribute EventHandler onrelease;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue