From 0068d595b696b4143c87a2e91f2007dfdb3e0384 Mon Sep 17 00:00:00 2001 From: Manuel Martin Date: Tue, 21 Apr 2020 19:22:44 +0200 Subject: [PATCH] Fixes #2545 Multiple media elements handling (#3201) * Reset the media state when location changes * Better media elements handling --- .../org/mozilla/vrbrowser/browser/Media.java | 7 +++++ .../browser/VideoAvailabilityListener.java | 4 ++- .../vrbrowser/browser/engine/Session.java | 28 +++++++++++++++---- .../vrbrowser/ui/widgets/WindowWidget.java | 24 ++++++---------- .../mozilla/vrbrowser/ui/widgets/Windows.java | 12 +++++--- 5 files changed, 49 insertions(+), 26 deletions(-) diff --git a/app/src/common/shared/org/mozilla/vrbrowser/browser/Media.java b/app/src/common/shared/org/mozilla/vrbrowser/browser/Media.java index 1eebc6d14..85368c907 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/browser/Media.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/browser/Media.java @@ -23,11 +23,13 @@ public class Media implements MediaElement.Delegate { private MediaElement mMedia; private CopyOnWriteArrayList mMediaListeners; private ResizeDelegate mResizeDelegate; + private long mLastStateUpdate; public Media(@NonNull MediaElement aMediaElement) { mMedia = aMediaElement; mMediaListeners = new CopyOnWriteArrayList<>(); aMediaElement.setDelegate(this); + mLastStateUpdate = 0; } public void addMediaListener(MediaElement.Delegate aListener) { @@ -113,6 +115,10 @@ public void setMuted(boolean aIsMuted) { mMedia.setMuted(aIsMuted); } + public long getLastStateUpdate() { + return mLastStateUpdate; + } + public void unload() { mIsUnloaded = true; mMediaListeners.clear(); @@ -149,6 +155,7 @@ public void onPlaybackStateChange(MediaElement mediaElement, int playbackState) mPlaying = false; mIsUnloaded = true; } + mLastStateUpdate = System.currentTimeMillis(); mMediaListeners.forEach(listener -> listener.onPlaybackStateChange(mediaElement, playbackState)); } diff --git a/app/src/common/shared/org/mozilla/vrbrowser/browser/VideoAvailabilityListener.java b/app/src/common/shared/org/mozilla/vrbrowser/browser/VideoAvailabilityListener.java index 53cc1b8a3..f004ce5b1 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/browser/VideoAvailabilityListener.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/browser/VideoAvailabilityListener.java @@ -1,5 +1,7 @@ package org.mozilla.vrbrowser.browser; +import androidx.annotation.NonNull; + public interface VideoAvailabilityListener { - default void onVideoAvailabilityChanged(boolean aVideosAvailable) {} + default void onVideoAvailabilityChanged(@NonNull Media media, boolean aVideoAvailable) {} } diff --git a/app/src/common/shared/org/mozilla/vrbrowser/browser/engine/Session.java b/app/src/common/shared/org/mozilla/vrbrowser/browser/engine/Session.java index 06bfe34f2..be1284e14 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/browser/engine/Session.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/browser/engine/Session.java @@ -49,10 +49,12 @@ import java.net.URI; import java.net.URISyntaxException; +import java.util.Comparator; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Predicate; import static java.util.Objects.requireNonNull; import static org.mozilla.vrbrowser.utils.ServoUtils.createServoSession; @@ -247,7 +249,9 @@ private void dumpState(GeckoSession.ContentDelegate aListener) { } private void dumpState(VideoAvailabilityListener aListener) { - aListener.onVideoAvailabilityChanged(mState.mMediaElements != null && mState.mMediaElements.size() > 0); + mState.mMediaElements.forEach(element -> { + aListener.onVideoAvailabilityChanged(element,true); + }); } private void dumpState(WebXRStateChangedListener aListener) { @@ -690,6 +694,7 @@ public boolean isFirstContentfulPaint() { return mFirstContentfulPaint; } + @Nullable public Media getFullScreenVideo() { for (Media media: mState.mMediaElements) { if (media.isFullscreen()) { @@ -703,6 +708,19 @@ public Media getFullScreenVideo() { return null; } + @Nullable + public Media getActiveVideo() { + for (Media media: mState.mMediaElements) { + if (media.isFullscreen()) { + return media; + } + } + return mState.mMediaElements.stream() + .sorted((o1, o2) -> (int)o2.getLastStateUpdate() - (int)o1.getLastStateUpdate()) + .filter(Media::isPlayed) + .findFirst().orElse(null); + } + public boolean isInputActive() { return mState.mIsInputActive; } @@ -1448,7 +1466,7 @@ public void onMediaAdd(@NonNull GeckoSession aSession, @NonNull MediaElement ele mState.mMediaElements.add(media); for (VideoAvailabilityListener listener: mVideoAvailabilityListeners) { - listener.onVideoAvailabilityChanged(true); + listener.onVideoAvailabilityChanged(media, true); } } @@ -1462,10 +1480,8 @@ public void onMediaRemove(@NonNull GeckoSession aSession, @NonNull MediaElement if (media.getMediaElement() == element) { media.unload(); mState.mMediaElements.remove(i); - if (mState.mMediaElements.size() == 0) { - for (VideoAvailabilityListener listener: mVideoAvailabilityListeners) { - listener.onVideoAvailabilityChanged(false); - } + for (VideoAvailabilityListener listener: mVideoAvailabilityListeners) { + listener.onVideoAvailabilityChanged(media, false); } return; } diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/WindowWidget.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/WindowWidget.java index 42d0e2969..b91c246ee 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/WindowWidget.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/WindowWidget.java @@ -1668,37 +1668,29 @@ public void onExternalResponse(@NonNull GeckoSession geckoSession, @NonNull Geck // VideoAvailabilityListener - private Media mMedia; - @Override - public void onVideoAvailabilityChanged(boolean aVideosAvailable) { + public void onVideoAvailabilityChanged(@NonNull Media aMedia, boolean aVideoAvailable) { boolean mediaAvailable; if (mSession != null) { - if (mMedia != null) { - mMedia.removeMediaListener(mMediaDelegate); - } - - mMedia = mSession.getFullScreenVideo(); - if (aVideosAvailable && mMedia != null) { - mMedia.addMediaListener(mMediaDelegate); - mediaAvailable = true; + if (aVideoAvailable) { + aMedia.addMediaListener(mMediaDelegate); } else { - mediaAvailable = false; + aMedia.removeMediaListener(mMediaDelegate); } + mediaAvailable = mSession.getActiveVideo() != null; } else { mediaAvailable = false; } if (mediaAvailable) { - if (mSession.getFullScreenVideo().isPlayed()) { - mViewModel.setIsMediaAvailable(true); + if (mSession.getActiveVideo().isPlayed()) { mViewModel.setIsMediaPlaying(true); } + mViewModel.setIsMediaAvailable(true); } else { - mMedia = null; mViewModel.setIsMediaAvailable(false); mViewModel.setIsMediaPlaying(false); } @@ -1754,6 +1746,8 @@ public void captureImage() { public void onLocationChange(@NonNull GeckoSession session, @Nullable String url) { mViewModel.setUrl(url); mViewModel.setIsDrmUsed(false); + mViewModel.setIsMediaAvailable(false); + mViewModel.setIsMediaPlaying(false); if (StringUtils.isEmpty(url)) { mViewModel.setIsBookmarked(false); diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/Windows.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/Windows.java index c690386b0..f35bc6848 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/Windows.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/Windows.java @@ -1085,8 +1085,10 @@ public void onTitleClicked(@NonNull TitleBarWidget titleBar) { @Override public void onMediaPlayClicked(@NonNull TitleBarWidget titleBar) { for (WindowWidget window : getCurrentWindows()) { - if (window.getTitleBar() == titleBar) { - window.getSession().getFullScreenVideo().play(); + if (window.getTitleBar() == titleBar && + window.getSession() != null && + window.getSession().getActiveVideo() != null) { + window.getSession().getActiveVideo().play(); } } } @@ -1094,8 +1096,10 @@ public void onMediaPlayClicked(@NonNull TitleBarWidget titleBar) { @Override public void onMediaPauseClicked(@NonNull TitleBarWidget titleBar) { for (WindowWidget window : getCurrentWindows()) { - if (window.getTitleBar() == titleBar) { - window.getSession().getFullScreenVideo().pause(); + if (window.getTitleBar() == titleBar && + window.getSession() != null && + window.getSession().getActiveVideo() != null) { + window.getSession().getActiveVideo().pause(); } } }