Commit db9b03b0 authored by Mounir Lamouri's avatar Mounir Lamouri Committed by Commit Bot

Video Wake Lock: cancel wake lock when context is paused/destroyed.

Bug: 980024
Change-Id: I49fdaac8ea558a6068a3de6ba7d74e922ee9de81
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1691255Reviewed-by: default avatarJeremy Roman <jbroman@chromium.org>
Commit-Queue: Mounir Lamouri <mlamouri@chromium.org>
Cr-Commit-Position: refs/heads/master@{#675699}
parent 769107aa
......@@ -603,6 +603,8 @@ void HTMLVideoElement::DidMoveToNewDocument(Document& old_document) {
ActivateViewportIntersectionMonitoring(true);
}
wake_lock_->ElementDidMoveToNewDocument();
HTMLMediaElement::DidMoveToNewDocument(old_document);
}
......
......@@ -5,6 +5,7 @@
#include "third_party/blink/renderer/core/html/media/video_wake_lock.h"
#include "services/service_manager/public/cpp/interface_provider.h"
#include "third_party/blink/public/mojom/wake_lock/wake_lock.mojom-blink.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/events/event.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
......@@ -12,12 +13,11 @@
#include "third_party/blink/renderer/core/html/media/html_video_element.h"
#include "third_party/blink/renderer/core/html/media/remote_playback_controller.h"
#include "third_party/blink/public/mojom/wake_lock/wake_lock.mojom-blink.h"
namespace blink {
VideoWakeLock::VideoWakeLock(HTMLVideoElement& video)
: PageVisibilityObserver(video.GetDocument().GetPage()),
ContextLifecycleStateObserver(&video.GetDocument()),
video_element_(video) {
VideoElement().addEventListener(event_type_names::kPlaying, this, true);
VideoElement().addEventListener(event_type_names::kPause, this, true);
......@@ -30,6 +30,13 @@ VideoWakeLock::VideoWakeLock(HTMLVideoElement& video)
RemotePlaybackController::From(VideoElement());
if (remote_playback_controller)
remote_playback_controller->AddObserver(this);
UpdateStateIfNeeded();
}
void VideoWakeLock::ElementDidMoveToNewDocument() {
ContextLifecycleStateObserver::DidMoveToNewExecutionContext(
&VideoElement().GetDocument());
}
void VideoWakeLock::PageVisibilityChanged() {
......@@ -39,6 +46,7 @@ void VideoWakeLock::PageVisibilityChanged() {
void VideoWakeLock::Trace(Visitor* visitor) {
NativeEventListener::Trace(visitor);
PageVisibilityObserver::Trace(visitor);
ContextLifecycleStateObserver::Trace(visitor);
visitor->Trace(video_element_);
}
......@@ -61,6 +69,14 @@ void VideoWakeLock::OnRemotePlaybackStateChanged(
Update();
}
void VideoWakeLock::ContextLifecycleStateChanged(mojom::FrameLifecycleState) {
Update();
}
void VideoWakeLock::ContextDestroyed(ExecutionContext*) {
Update();
}
void VideoWakeLock::Update() {
bool should_be_active = ShouldBeActive();
if (should_be_active == active_)
......@@ -74,9 +90,12 @@ bool VideoWakeLock::ShouldBeActive() const {
bool page_visible = GetPage() && GetPage()->IsPageVisible();
bool in_picture_in_picture =
PictureInPictureController::IsElementInPictureInPicture(&VideoElement());
return playing_ && (page_visible || in_picture_in_picture) &&
remote_playback_state_ !=
mojom::blink::PresentationConnectionState::CONNECTED;
mojom::blink::PresentationConnectionState::CONNECTED &&
!(VideoElement().GetDocument().IsContextPaused() ||
VideoElement().GetDocument().IsContextDestroyed());
}
void VideoWakeLock::EnsureWakeLockService() {
......@@ -87,8 +106,12 @@ void VideoWakeLock::EnsureWakeLockService() {
if (!frame)
return;
scoped_refptr<base::SingleThreadTaskRunner> task_runner =
frame->GetTaskRunner(TaskType::kMediaElementEvent);
blink::mojom::blink::WakeLockServicePtr service;
frame->GetInterfaceProvider().GetInterface(mojo::MakeRequest(&service));
frame->GetInterfaceProvider().GetInterface(
mojo::MakeRequest(&service, task_runner));
service->GetWakeLock(device::mojom::WakeLockType::kPreventDisplaySleep,
device::mojom::blink::WakeLockReason::kVideoPlayback,
"Video Wake Lock",
......
......@@ -8,6 +8,7 @@
#include "services/device/public/mojom/wake_lock.mojom-blink.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/dom/events/native_event_listener.h"
#include "third_party/blink/renderer/core/execution_context/context_lifecycle_state_observer.h"
#include "third_party/blink/renderer/core/html/media/remote_playback_observer.h"
#include "third_party/blink/renderer/core/page/page_visibility_observer.h"
......@@ -19,19 +20,23 @@ class HTMLVideoElement;
// take wake lock iif:
// - the video is playing;
// - the page is visible OR the video is in picture-in-picture;
// - the video isn't being remoted.
// - the video isn't being remoted;
// - the execution context is neither paused nor destroyed.
// Each video element implements its own wake lock logic. The service will then
// merge all the requests and take the appropriate system wake lock.
// VideoWakeLock only uses "screen" related wake lock: it prevents the screen
// from locking on mobile or the lockscreen to show up on desktop.
class CORE_EXPORT VideoWakeLock final : public NativeEventListener,
public PageVisibilityObserver,
public RemotePlaybackObserver {
public RemotePlaybackObserver,
public ContextLifecycleStateObserver {
USING_GARBAGE_COLLECTED_MIXIN(VideoWakeLock);
public:
explicit VideoWakeLock(HTMLVideoElement&);
void ElementDidMoveToNewDocument();
void Trace(Visitor*) final;
// EventListener implementation.
......@@ -41,6 +46,10 @@ class CORE_EXPORT VideoWakeLock final : public NativeEventListener,
void OnRemotePlaybackStateChanged(
mojom::blink::PresentationConnectionState) final;
// ContextLifecycleStateObserver
void ContextLifecycleStateChanged(mojom::FrameLifecycleState) override;
void ContextDestroyed(ExecutionContext*) override;
bool active_for_tests() const { return active_; }
private:
......
......@@ -153,6 +153,16 @@ class VideoWakeLockTest : public PageTestBase {
video_.Get(), event_type_names::kLeavepictureinpicture);
}
void SimulateContextPause() {
GetDocument().SetLifecycleState(mojom::FrameLifecycleState::kPaused);
}
void SimulateContextRunning() {
GetDocument().SetLifecycleState(mojom::FrameLifecycleState::kRunning);
}
void SimulateContextDestroyed() { GetDocument().NotifyContextDestroyed(); }
private:
Persistent<HTMLVideoElement> video_;
Persistent<VideoWakeLock> video_wake_lock_;
......@@ -311,4 +321,31 @@ TEST_F(VideoWakeLockTest, RemotingVideoInPictureInPictureDoesNotRequestLock) {
EXPECT_FALSE(GetVideoWakeLock()->active_for_tests());
}
TEST_F(VideoWakeLockTest, PausingContextCancelsLock) {
SimulatePlaying();
EXPECT_TRUE(GetVideoWakeLock()->active_for_tests());
SimulateContextPause();
EXPECT_FALSE(GetVideoWakeLock()->active_for_tests());
}
TEST_F(VideoWakeLockTest, ResumingContextResumesLock) {
SimulatePlaying();
EXPECT_TRUE(GetVideoWakeLock()->active_for_tests());
SimulateContextPause();
EXPECT_FALSE(GetVideoWakeLock()->active_for_tests());
SimulateContextRunning();
EXPECT_TRUE(GetVideoWakeLock()->active_for_tests());
}
TEST_F(VideoWakeLockTest, DestroyingContextCancelsLock) {
SimulatePlaying();
EXPECT_TRUE(GetVideoWakeLock()->active_for_tests());
SimulateContextDestroyed();
EXPECT_FALSE(GetVideoWakeLock()->active_for_tests());
}
} // namespace blink
......@@ -2,7 +2,7 @@ Tests that reparenting media elements also reparents ActiveDOMObject.
Before Reparenting
PASS: internals.contextLifecycleStateObserverObjectCount(document) should be '0' and is.
PASS: internals.contextLifecycleStateObserverObjectCount(iframe) should be '1' and is.
PASS: internals.contextLifecycleStateObserverObjectCount(iframe) should be '2' and is.
After Reparenting
PASS: internals.contextLifecycleStateObserverObjectCount(document) should be '1' and is.
PASS: internals.contextLifecycleStateObserverObjectCount(document) should be '2' and is.
PASS: internals.contextLifecycleStateObserverObjectCount(iframe) should be '0' and is.
......@@ -11,12 +11,12 @@
log('Before Reparenting');
shouldBe('internals.contextLifecycleStateObserverObjectCount(document)', 0);
shouldBe('internals.contextLifecycleStateObserverObjectCount(iframe)', 1);
shouldBe('internals.contextLifecycleStateObserverObjectCount(iframe)', 2);
document.body.appendChild(window.iframe.querySelector('video'));
log('After Reparenting');
shouldBe('internals.contextLifecycleStateObserverObjectCount(document)', 1);
shouldBe('internals.contextLifecycleStateObserverObjectCount(document)', 2);
shouldBe('internals.contextLifecycleStateObserverObjectCount(iframe)', 0);
}
</script>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment