Bug 1623715 - [8.2] Move media fullscreen event to JS and extend its metadata. r=geckoview-reviewers,snorp,alwu

Differential Revision: https://phabricator.services.mozilla.com/D86350
This commit is contained in:
Eugen Sawin 2020-08-18 17:29:33 +00:00
Родитель 308a5f3d79
Коммит 7609049ab6
6 изменённых файлов: 188 добавлений и 39 удалений

Просмотреть файл

@ -0,0 +1,72 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* 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/. */
"use strict";
const { GeckoViewChildModule } = ChromeUtils.import(
"resource://gre/modules/GeckoViewChildModule.jsm"
);
const { XPCOMUtils } = ChromeUtils.import(
"resource://gre/modules/XPCOMUtils.jsm"
);
XPCOMUtils.defineLazyModuleGetters(this, {
MediaUtils: "resource://gre/modules/MediaUtils.jsm",
});
class GeckoViewMediaControl extends GeckoViewChildModule {
onInit() {
debug`onEnable`;
}
onEnable() {
debug`onEnable`;
addEventListener("MozDOMFullscreen:Entered", this, false);
addEventListener("MozDOMFullscreen:Exited", this, false);
}
onDisable() {
debug`onDisable`;
removeEventListener("MozDOMFullscreen:Entered", this);
removeEventListener("MozDOMFullscreen:Exited", this);
}
handleEvent(aEvent) {
debug`handleEvent: ${aEvent.type}`;
switch (aEvent.type) {
case "MozDOMFullscreen:Entered":
case "MozDOMFullscreen:Exited":
this.handleFullscreenChanged();
break;
}
}
handleFullscreenChanged() {
const element = content && content.document.fullscreenElement;
const mediaElement = MediaUtils.findMediaElement(element);
if (element && !mediaElement) {
// Non-media element fullscreen.
return;
}
const message = {
metadata: MediaUtils.getMetadata(mediaElement) ?? {},
enabled: !!element,
};
this.messageManager.sendAsyncMessage(
"GeckoView:MediaControl:Fullscreen",
message
);
}
}
const { debug } = GeckoViewMediaControl.initLogging("GeckoViewMediaControl");
const module = GeckoViewMediaControl.create(this);

Просмотреть файл

@ -653,6 +653,7 @@ function startup() {
name: "GeckoViewMediaControl",
onEnable: {
resource: "resource://gre/modules/GeckoViewMediaControl.jsm",
frameScript: "chrome://geckoview/content/GeckoViewMediaControlChild.js",
},
},
]);

Просмотреть файл

@ -14,6 +14,7 @@ geckoview.jar:
content/geckoview.js
content/GeckoViewAutofillChild.js
content/GeckoViewMediaChild.js
content/GeckoViewMediaControlChild.js
content/GeckoViewProgressChild.js
content/GeckoViewPromptChild.js
content/GeckoViewScrollChild.js

Просмотреть файл

@ -403,11 +403,13 @@ public class MediaSession {
* @param session The associated GeckoSession.
* @param mediaSession The media session for the given GeckoSession.
* @param enabled True when this media session in in fullscreen mode.
* @param meta An instance of {@link ElementMetadata}, if enabled.
*/
default void onFullscreen(
@NonNull GeckoSession session,
@NonNull MediaSession mediaSession,
boolean enabled) {}
boolean enabled,
@Nullable ElementMetadata meta) {}
/**
* Notify on changed picture-in-picture mode state.
@ -424,6 +426,78 @@ public class MediaSession {
}
/**
* The representation of a media element's metadata.
*/
public static class ElementMetadata {
/**
* The media source URI.
*/
public final @Nullable String source;
/**
* The duration of the media in seconds.
*/
public final double duration;
/**
* The width of the video in device pixels.
*/
public final long width;
/**
* The height of the video in device pixels.
*/
public final long height;
/**
* The number of audio tracks contained in this element.
*/
public final int audioTrackCount;
/**
* The number of video tracks contained in this element.
*/
public final int videoTrackCount;
/**
* ElementMetadata constructor.
*
* @param source The media URI.
* @param duration The media duration in seconds.
* @param width The video width in device pixels.
* @param height The video height in device pixels.
* @param audioTrackCount The audio track count.
* @param videoTrackCount The video track count.
*/
public ElementMetadata(
@Nullable final String source,
final double duration,
final long width,
final long height,
final int audioTrackCount,
final int videoTrackCount) {
this.source = source;
this.duration = duration;
this.width = width;
this.height = height;
this.audioTrackCount = audioTrackCount;
this.videoTrackCount = videoTrackCount;
}
/* package */ static @NonNull ElementMetadata fromBundle(
final GeckoBundle bundle) {
// Sync with MediaUtils.jsm.
return new ElementMetadata(
bundle.getString("src"),
bundle.getDouble("duration", 0.0),
bundle.getLong("width", 0),
bundle.getLong("height", 0),
bundle.getInt("audioTrackCount", 0),
bundle.getInt("videoTrackCount", 0));
}
}
/**
* The representation of a media session's metadata.
*/
@ -750,7 +824,10 @@ public class MediaSession {
delegate.onFeatures(mSession, mMediaSession, features);
} else if (FULLSCREEN_EVENT.equals(event)) {
final boolean enabled = message.getBoolean("enabled");
delegate.onFullscreen(mSession, mMediaSession, enabled);
final ElementMetadata meta =
ElementMetadata.fromBundle(
message.getBundle("metadata"));
delegate.onFullscreen(mSession, mMediaSession, enabled, meta);
} else if (PICTURE_IN_PICTURE_EVENT.equals(event)) {
final boolean enabled = message.getBoolean("enabled");
delegate.onPictureInPicture(mSession, mMediaSession, enabled);

Просмотреть файл

@ -32,6 +32,11 @@ class GeckoViewMediaControl extends GeckoViewModule {
this.controller.addEventListener("supportedkeyschange", this, options);
this.controller.addEventListener("positionstatechange", this, options);
// TODO: Move other events to webidl once supported.
this.messageManager.addMessageListener(
"GeckoView:MediaControl:Fullscreen",
this
);
}
onDisable() {
@ -41,12 +46,30 @@ class GeckoViewMediaControl extends GeckoViewModule {
this.controller.removeEventListener("deactivated", this);
this.controller.removeEventListener("supportedkeyschange", this);
this.controller.removeEventListener("positionstatechange", this);
this.messageManager.removeMessageListener(
"GeckoView:MediaControl:Fullscreen",
this
);
}
get controller() {
return this.browser.browsingContext.mediaController;
}
receiveMessage(aMsg) {
debug`receiveMessage: name=${aMsg.name}, data=${aMsg.data}`;
switch (aMsg.name) {
case "GeckoView:MediaControl:Fullscreen":
this.handleFullscreenChanged(aMsg.data);
break;
default:
warn`Unknown message name ${aMsg.name}`;
break;
}
}
// eslint-disable-next-line complexity
handleEvent(aEvent) {
debug`handleEvent: ${aEvent.type}`;
@ -70,6 +93,17 @@ class GeckoViewMediaControl extends GeckoViewModule {
}
}
handleFullscreenChanged(aData) {
debug`handleFullscreenChanged ${aData.enabled}`;
this.eventDispatcher.sendRequest({
type: "GeckoView:MediaSession:Fullscreen",
id: this.controller.id,
enabled: aData.enabled,
metadata: aData.metadata,
});
}
handleActivated() {
debug`handleActivated`;
@ -98,7 +132,7 @@ class GeckoViewMediaControl extends GeckoViewModule {
duration: aEvent.duration,
playbackRate: aEvent.playbackRate,
position: aEvent.position,
}
},
});
}

Просмотреть файл

@ -388,7 +388,6 @@ class nsWindow::MediaSessionSupport final
ControllerPtr mMediaController;
MediaEventListener mMetadataChangedListener;
MediaEventListener mPlaybackChangedListener;
MediaEventListener mFullscreenChangedListener;
public:
typedef java::MediaSession::Controller::Natives<MediaSessionSupport> Base;
@ -536,35 +535,6 @@ class nsWindow::MediaSessionSupport final
}
}
void FullscreenChanged(bool aIsEnabled) {
MOZ_ASSERT(NS_IsMainThread());
const size_t kBundleSize = 1;
AutoTArray<jni::String::LocalRef, kBundleSize> keys;
AutoTArray<jni::Object::LocalRef, kBundleSize> values;
keys.AppendElement(
jni::StringParam(NS_LITERAL_STRING_FROM_CSTRING("enabled")));
values.AppendElement(aIsEnabled ? java::sdk::Boolean::TRUE()
: java::sdk::Boolean::FALSE());
MOZ_ASSERT(kBundleSize == keys.Length());
MOZ_ASSERT(kBundleSize == values.Length());
auto bundleKeys = jni::ObjectArray::New<jni::String>(kBundleSize);
auto bundleValues = jni::ObjectArray::New<jni::Object>(kBundleSize);
for (size_t i = 0; i < kBundleSize; ++i) {
bundleKeys->SetElement(i, keys[i]);
bundleValues->SetElement(i, values[i]);
}
auto bundle = java::GeckoBundle::New(bundleKeys, bundleValues);
const char16_t kFullscreen[] = u"GeckoView:MediaSession:Fullscreen";
Dispatch(kFullscreen, bundle);
}
void OnDetach(already_AddRefed<Runnable> aDisposer) {
MOZ_ASSERT(NS_IsMainThread());
@ -623,17 +593,11 @@ class nsWindow::MediaSessionSupport final
mPlaybackChangedListener = mMediaController->PlaybackChangedEvent().Connect(
AbstractThread::MainThread(), this,
&MediaSessionSupport::PlaybackChanged);
mFullscreenChangedListener =
mMediaController->FullScreenChangedEvent().Connect(
AbstractThread::MainThread(), this,
&MediaSessionSupport::FullscreenChanged);
}
void UnregisterControllerListeners() {
mMetadataChangedListener.DisconnectIfExists();
mPlaybackChangedListener.DisconnectIfExists();
mFullscreenChangedListener.DisconnectIfExists();
}
bool IsActive() const {