W3C home > Mailing lists > Public > whatwg@whatwg.org > August 2014

Re: [whatwg] Proposal: Wake Lock API

From: Kornel Lesiński <kornel@geekhood.net>
Date: Tue, 19 Aug 2014 03:02:14 +0100
Message-Id: <B2D63607-F17D-49B8-8F92-F83CF280A6FD@geekhood.net>
To: Marcos Caceres <w3c@marcosc.com>
Cc: WHAT Working Group <whatwg@lists.whatwg.org>, Mounir Lamouri <mounir@lamouri.fr>, Jonas Sicking <jonas@sicking.cc>
> On Monday, August 18, 2014 at 6:24 PM, Kornel Lesiński wrote:
>> I think it'd be unfortunate if this API had just one shared lock per browsing context and required components on the page to coordinate locking, but provided no means to do so.  
> The API allows scripts to check which locks are currently held (as either a `isHeld()` or `getCurrentLocks()`, for which I just sent a PR for).   

I don't understand how is that helping.

Let's say I have embedded a Slideshare presentation and a YouTube video on my page. I start watching slides, then start playing the video, then finish watching slides.

When Slideshare finishes and wants to release the lock, it can't learn via this API whether YouTube still wants the lock. When Slideshare started isHeld was false, but setting it back to that original state would be incorrect. When Slideshare finished isHeld was true, but that doesn't tell anything either, since Slideshare itself set it to true.

The only way I see for coordinating lock between independent components on the page is not via isHeld(), but by defensively re-setting the lock.

In my previous example both Slideshare and YouTube would have to watch for 'lost' events (but not via the Netscape-style onlost footgun!) and keep re-requesting the lock soon after it's been released, for as long as they need it.

IMHO that's really ugly.

If re-requesting is supposed to be the pattern for maintaining locks properly, then the whole API could be cut down to just events:

window.addEventListener('beforeScreenLock', function(e) {
	if (stillShowingStuff) e.preventDefault();
}, false);

The browser would fire beforeScreenLock event every time the OS is about to turn the screen off. To keep the screen on for another while the page just needs to prevent the event.

>> This will force authors of libraries and components to create dummy iframes just to have their private lock, and libraries/pages without such workaround will be messing up each other's locks.
> Currently, iframes are not allowed to have locks - only top-level browsing contexts are. This is to avoid things like embedded ads from requesting wake locks.   

That's a noble goal. However, it may not be effective against ads in practice, because majority of ads are embedded using <script>. OTOH it may prevent use of locks in well-behaved embedded documents (slideshows and the like). 

At very least I suggest controlling this like other potentially-annoying features via <iframe sandbox=allow-locks>.

>> To make some coordination possible, the simplest method could be to keep track of number of lock requests and releases, like retain/release in Objective-C:
>> navigator.wakeLock.request("screen"); // locks
>> navigator.wakeLock.request("screen"); // increases lock count
>> navigator.wakeLock.release("screen"); // not released yet, but decreases lock count
>> navigator.wakeLock.release("screen"); // now released for real
> In my dummy implementation, I've just been using (the Swift equivalent of):
> [UIApplication sharedApplication].idleTimerDisabled = YES;

I admire elegance of most of Cocoa's APIs, but I don't think design of that one is worth copying. It's global shared mutable state, and there's even negation in the property name—it may have been a quick hack that slipped though Cocoa QA (the documentation even includes a warning that it should be used with care and only when necessary).

Apple has tight control over what apps do, and iOS apps generally don't have as many code mashups as web pages, so such primitive fragile API may be less of a concern for Apple.

Other APIs you've liked to (https://developer.apple.com/library/mac/qa/qa1340/_index.html) are better:

IOPMAssertionCreateWithName/IOPMAssertionRelease creates instances that can be individually independently released, so each component can have its own lock and they can't release each other's locks accidentally (similar to the `new WakeLock()` proposal).

IORegisterForSystemPower uses a callback (similar to the `event.preventDefault()` solution I've outlined earlier in this mail).

>> This makes coordination easier: each page component can easily create their own lock independently (without needing to create an iframe to get their own lock), and can't release any other component's lock.
> Personally, I don't know if I agree that it makes coordination easier. Seems that having a centralized place to check what is currently being held makes life a lot easier, because it allows scripts to check if they actually need to request a lock or not.

No! That's a footgun! You can't do `if (!isHeld()) request()`, because the other component holding the lock may have shorter lifetime than yours, and you can't know that.

regards, Kornel
Received on Tuesday, 19 August 2014 02:02:53 UTC

This archive was generated by hypermail 2.4.0 : Wednesday, 22 January 2020 17:00:22 UTC