blob: f7eaf58d17ddc3aed5e7f9fcf284b2dda9bb5f67 [file] [log] [blame]
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/modules/media_controls/media_controls_media_event_listener.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/settings.h"
#include "third_party/blink/renderer/core/html/media/html_media_element.h"
#include "third_party/blink/renderer/core/html/track/text_track_list.h"
#include "third_party/blink/renderer/modules/media_controls/media_controls_impl.h"
#include "third_party/blink/renderer/modules/remoteplayback/availability_callback_wrapper.h"
#include "third_party/blink/renderer/modules/remoteplayback/remote_playback.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
namespace blink {
MediaControlsMediaEventListener::MediaControlsMediaEventListener(
MediaControlsImpl* media_controls)
: media_controls_(media_controls) {
if (GetMediaElement().isConnected())
Attach();
}
void MediaControlsMediaEventListener::Attach() {
DCHECK(GetMediaElement().isConnected());
GetMediaElement().addEventListener(event_type_names::kVolumechange, this,
false);
GetMediaElement().addEventListener(event_type_names::kFocusin, this, false);
GetMediaElement().addEventListener(event_type_names::kTimeupdate, this,
false);
GetMediaElement().addEventListener(event_type_names::kPlay, this, false);
GetMediaElement().addEventListener(event_type_names::kPlaying, this, false);
GetMediaElement().addEventListener(event_type_names::kPause, this, false);
GetMediaElement().addEventListener(event_type_names::kDurationchange, this,
false);
GetMediaElement().addEventListener(event_type_names::kSeeking, this, false);
GetMediaElement().addEventListener(event_type_names::kSeeked, this, false);
GetMediaElement().addEventListener(event_type_names::kError, this, false);
GetMediaElement().addEventListener(event_type_names::kLoadedmetadata, this,
false);
GetMediaElement().addEventListener(event_type_names::kKeypress, this, false);
GetMediaElement().addEventListener(event_type_names::kKeydown, this, false);
GetMediaElement().addEventListener(event_type_names::kKeyup, this, false);
GetMediaElement().addEventListener(event_type_names::kWaiting, this, false);
GetMediaElement().addEventListener(event_type_names::kProgress, this, false);
GetMediaElement().addEventListener(event_type_names::kLoadeddata, this,
false);
// Listen to two different fullscreen events in order to make sure the new and
// old APIs are handled.
GetMediaElement().addEventListener(event_type_names::kWebkitfullscreenchange,
this, false);
media_controls_->GetDocument().addEventListener(
event_type_names::kFullscreenchange, this, false);
// Picture-in-Picture events.
if (RuntimeEnabledFeatures::PictureInPictureEnabled() &&
media_controls_->GetDocument().GetSettings() &&
media_controls_->GetDocument()
.GetSettings()
->GetPictureInPictureEnabled() &&
IsA<HTMLVideoElement>(GetMediaElement())) {
GetMediaElement().addEventListener(event_type_names::kEnterpictureinpicture,
this, false);
GetMediaElement().addEventListener(event_type_names::kLeavepictureinpicture,
this, false);
}
// TextTracks events.
TextTrackList* text_tracks = GetMediaElement().textTracks();
text_tracks->addEventListener(event_type_names::kAddtrack, this, false);
text_tracks->addEventListener(event_type_names::kChange, this, false);
text_tracks->addEventListener(event_type_names::kRemovetrack, this, false);
// Keypress events.
if (media_controls_->ButtonPanelElement()) {
media_controls_->ButtonPanelElement()->addEventListener(
event_type_names::kKeypress, this, false);
}
RemotePlayback& remote = RemotePlayback::From(GetMediaElement());
remote.addEventListener(event_type_names::kConnect, this);
remote.addEventListener(event_type_names::kConnecting, this);
remote.addEventListener(event_type_names::kDisconnect, this);
// TODO(avayvod, mlamouri): Attach can be called twice. See
// https://crbug.com/713275.
if (!remote_playback_availability_callback_id_.has_value()) {
remote_playback_availability_callback_id_ =
base::make_optional(remote.WatchAvailabilityInternal(
MakeGarbageCollected<AvailabilityCallbackWrapper>(
WTF::BindRepeating(&MediaControlsMediaEventListener::
OnRemotePlaybackAvailabilityChanged,
WrapWeakPersistent(this)))));
}
}
void MediaControlsMediaEventListener::Detach() {
DCHECK(!GetMediaElement().isConnected());
media_controls_->GetDocument().removeEventListener(
event_type_names::kFullscreenchange, this, false);
TextTrackList* text_tracks = GetMediaElement().textTracks();
text_tracks->removeEventListener(event_type_names::kAddtrack, this, false);
text_tracks->removeEventListener(event_type_names::kChange, this, false);
text_tracks->removeEventListener(event_type_names::kRemovetrack, this, false);
if (media_controls_->ButtonPanelElement()) {
media_controls_->ButtonPanelElement()->removeEventListener(
event_type_names::kKeypress, this, false);
}
RemotePlayback& remote = RemotePlayback::From(GetMediaElement());
remote.removeEventListener(event_type_names::kConnect, this);
remote.removeEventListener(event_type_names::kConnecting, this);
remote.removeEventListener(event_type_names::kDisconnect, this);
// TODO(avayvod): apparently Detach() can be called without a previous
// Attach() call. See https://crbug.com/713275 for more details.
if (remote_playback_availability_callback_id_.has_value() &&
remote_playback_availability_callback_id_.value() !=
RemotePlayback::kWatchAvailabilityNotSupported) {
remote.CancelWatchAvailabilityInternal(
remote_playback_availability_callback_id_.value());
remote_playback_availability_callback_id_.reset();
}
}
HTMLMediaElement& MediaControlsMediaEventListener::GetMediaElement() {
return media_controls_->MediaElement();
}
void MediaControlsMediaEventListener::Invoke(
ExecutionContext* execution_context,
Event* event) {
if (event->type() == event_type_names::kVolumechange) {
media_controls_->OnVolumeChange();
return;
}
if (event->type() == event_type_names::kFocusin) {
media_controls_->OnFocusIn();
return;
}
if (event->type() == event_type_names::kTimeupdate) {
media_controls_->OnTimeUpdate();
return;
}
if (event->type() == event_type_names::kDurationchange) {
media_controls_->OnDurationChange();
return;
}
if (event->type() == event_type_names::kPlay) {
media_controls_->OnPlay();
return;
}
if (event->type() == event_type_names::kPlaying) {
media_controls_->OnPlaying();
return;
}
if (event->type() == event_type_names::kPause) {
media_controls_->OnPause();
return;
}
if (event->type() == event_type_names::kSeeking) {
media_controls_->OnSeeking();
return;
}
if (event->type() == event_type_names::kSeeked) {
media_controls_->OnSeeked();
return;
}
if (event->type() == event_type_names::kError) {
media_controls_->OnError();
return;
}
if (event->type() == event_type_names::kLoadedmetadata) {
media_controls_->OnLoadedMetadata();
return;
}
if (event->type() == event_type_names::kWaiting) {
media_controls_->OnWaiting();
return;
}
if (event->type() == event_type_names::kProgress) {
media_controls_->OnLoadingProgress();
return;
}
if (event->type() == event_type_names::kLoadeddata) {
media_controls_->OnLoadedData();
return;
}
// Fullscreen handling.
if (event->type() == event_type_names::kFullscreenchange ||
event->type() == event_type_names::kWebkitfullscreenchange) {
if (GetMediaElement().IsFullscreen())
media_controls_->OnEnteredFullscreen();
else
media_controls_->OnExitedFullscreen();
return;
}
// Picture-in-Picture events.
if (event->type() == event_type_names::kEnterpictureinpicture ||
event->type() == event_type_names::kLeavepictureinpicture) {
media_controls_->OnPictureInPictureChanged();
return;
}
// TextTracks events.
if (event->type() == event_type_names::kAddtrack ||
event->type() == event_type_names::kRemovetrack) {
media_controls_->OnTextTracksAddedOrRemoved();
return;
}
if (event->type() == event_type_names::kChange) {
media_controls_->OnTextTracksChanged();
return;
}
// Keypress events.
if (event->type() == event_type_names::kKeypress) {
if (event->currentTarget() == media_controls_->ButtonPanelElement()) {
media_controls_->OnPanelKeypress();
return;
}
}
if (event->type() == event_type_names::kKeypress ||
event->type() == event_type_names::kKeydown ||
event->type() == event_type_names::kKeyup) {
media_controls_->OnMediaKeyboardEvent(event);
return;
}
// RemotePlayback state change events.
if (event->type() == event_type_names::kConnect ||
event->type() == event_type_names::kConnecting ||
event->type() == event_type_names::kDisconnect) {
media_controls_->RemotePlaybackStateChanged();
return;
}
NOTREACHED();
}
void MediaControlsMediaEventListener::OnRemotePlaybackAvailabilityChanged() {
media_controls_->RefreshCastButtonVisibility();
}
void MediaControlsMediaEventListener::Trace(Visitor* visitor) const {
NativeEventListener::Trace(visitor);
visitor->Trace(media_controls_);
}
} // namespace blink