Skip to content
Snippets Groups Projects
Commit f5090d66 authored by Makoto Kato's avatar Makoto Kato
Browse files

Bug 1819814 - Call MediaSession.Delegate.onFullscreen correctly when entering...

Bug 1819814 - Call MediaSession.Delegate.onFullscreen correctly when entering full screen. r=geckoview-reviewers,calu

This is a race condition of full screen event and activated event of media
controller.

Media controller will dispatch activated event when full screen button is
clicked on controller. But since this depends on full screen event, if
GeckoView's media session receives this event before controller fires activated
event, `MediaSession.Delegate.onFullscreen` won't be called because
MediaSession.isActive() is false at this time.

So I would like to retry `GeckoView:MediaSession:Fullscreen` call when
entering full screen and controller isn't active yet.

Differential Revision: https://phabricator.services.mozilla.com/D173831
parent 6b7b637d
No related branches found
No related tags found
No related merge requests found
......@@ -14,6 +14,10 @@ const { XPCOMUtils } = ChromeUtils.importESModule(
const lazy = {};
ChromeUtils.defineESModuleGetters(lazy, {
setTimeout: "resource://gre/modules/Timer.sys.mjs",
});
XPCOMUtils.defineLazyModuleGetters(lazy, {
MediaUtils: "resource://gre/modules/MediaUtils.jsm",
});
......@@ -27,12 +31,12 @@ class MediaControlDelegateChild extends GeckoViewActorChild {
switch (aEvent.type) {
case "MozDOMFullscreen:Entered":
case "MozDOMFullscreen:Exited":
this.handleFullscreenChanged();
this.handleFullscreenChanged(true);
break;
}
}
handleFullscreenChanged() {
async handleFullscreenChanged(retry) {
debug`handleFullscreenChanged`;
const element = this.document.fullscreenElement;
......@@ -43,11 +47,23 @@ class MediaControlDelegateChild extends GeckoViewActorChild {
debug`No fullscreen media element found.`;
}
this.eventDispatcher.sendRequest({
const activated = await this.eventDispatcher.sendRequestForResult({
type: "GeckoView:MediaSession:Fullscreen",
metadata: lazy.MediaUtils.getMetadata(mediaElement) ?? {},
enabled: !!element,
});
if (activated) {
return;
}
if (retry && element) {
// When media session is going to active, we have a race condition of
// full screen event because media session will be activated by full
// screen event.
// So we retry to call media session delegate for this situation.
lazy.setTimeout(() => {
this.handleFullscreenChanged(false);
}, 100);
}
}
}
......
......@@ -953,4 +953,47 @@ class MediaSessionTest : BaseSessionTest() {
mediaSession1!!.pause()
sessionRule.waitForResult(completedStep5)
}
@Test
fun fullscreenVideoWithActivated() {
// TODO: bug 1810736
assumeThat(sessionRule.env.isIsolatedProcess, equalTo(false))
sessionRule.setPrefsUntilTestEnd(
mapOf(
"media.autoplay.default" to 0,
"full-screen-api.allow-trusted-requests-only" to false
)
)
val path = VIDEO_WEBM_PATH
val session = sessionRule.createOpenSession()
val resultFullscreen = GeckoResult<Void>()
session.loadTestPath(path)
sessionRule.waitForPageStop()
session.delegateDuringNextWait(object : MediaSession.Delegate {
override fun onFullscreen(
session: GeckoSession,
mediaSession: MediaSession,
enabled: Boolean,
meta: MediaSession.ElementMetadata?
) {
assertThat(
"Fullscreen should be enabled",
enabled,
equalTo(true)
)
assertThat(
"Element metadata should exist",
meta,
notNullValue()
)
resultFullscreen.complete(null)
}
})
session.evaluateJS("document.querySelector('video').requestFullscreen()")
sessionRule.waitForResult(resultFullscreen)
}
}
......@@ -629,10 +629,18 @@ public class MediaSession {
} else if (FEATURES_EVENT.equals(event)) {
final long features = Feature.fromBundle(message.getBundle("features"));
delegate.onFeatures(mSession, mMediaSession, features);
} else if (FULLSCREEN_EVENT.equals(event) && mMediaSession.isActive()) {
} else if (FULLSCREEN_EVENT.equals(event)) {
final boolean enabled = message.getBoolean("enabled");
final ElementMetadata meta = ElementMetadata.fromBundle(message.getBundle("metadata"));
if (!mMediaSession.isActive()) {
if (DEBUG) {
Log.d(LOGTAG, "Media session is not active yet");
}
callback.sendSuccess(false);
return;
}
delegate.onFullscreen(mSession, mMediaSession, enabled, meta);
callback.sendSuccess(true);
}
}
}
......
......@@ -17,6 +17,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentSender;
import android.content.SharedPreferences;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.graphics.Bitmap;
......@@ -82,6 +83,7 @@ import org.mozilla.geckoview.GeckoSessionSettings;
import org.mozilla.geckoview.GeckoView;
import org.mozilla.geckoview.GeckoWebExecutor;
import org.mozilla.geckoview.Image;
import org.mozilla.geckoview.MediaSession;
import org.mozilla.geckoview.OrientationController;
import org.mozilla.geckoview.RuntimeTelemetry;
import org.mozilla.geckoview.SlowScriptResponse;
......@@ -1118,6 +1120,8 @@ public class GeckoViewActivity extends AppCompatActivity
session.setMediaDelegate(new ExampleMediaDelegate(this));
session.setMediaSessionDelegate(new ExampleMediaSessionDelegate(this));
session.setSelectionActionDelegate(new BasicSelectionActionDelegate(this));
if (sExtensionManager.extension != null) {
final WebExtension.SessionController sessionController = session.getWebExtensionController();
......@@ -2468,6 +2472,38 @@ public class GeckoViewActivity extends AppCompatActivity
}
}
private class ExampleMediaSessionDelegate implements MediaSession.Delegate {
private final Activity mActivity;
public ExampleMediaSessionDelegate(Activity activity) {
mActivity = activity;
}
@Override
public void onFullscreen(
@NonNull final GeckoSession session,
@NonNull final MediaSession mediaSession,
final boolean enabled,
@Nullable final MediaSession.ElementMetadata meta) {
Log.d(LOGTAG, "onFullscreen: Metadata=" + (meta != null ? meta.toString() : "null"));
if (!enabled) {
mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_USER);
return;
}
if (meta == null) {
return;
}
if (meta.width > meta.height) {
mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
} else {
mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT);
}
}
}
private final class ExampleTelemetryDelegate implements RuntimeTelemetry.Delegate {
@Override
public void onHistogram(final @NonNull RuntimeTelemetry.Histogram histogram) {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment