From ca5b6837e1b4cd239b7639f8bd24f505bb8e91d4 Mon Sep 17 00:00:00 2001 From: Petru-Mugurel Lingurar Date: Fri, 15 Feb 2019 17:32:42 +0000 Subject: [PATCH] Bug 1503978 - Force fullscreen after PiP only if media is playing; r=JanH Otherwise the user should see and be able to interact with the whole page. Refactored `PictureInPictureController` to check the media playing status for only the current tab, the one the user has in front and for which we may allow PiP because `GeckoMediaControlAgent.isMediaPlaying()` would give us false positives in the case where the current Tab is in fullscreen but not playing media, while at the same time a background Tab is playing media. BrowserApp will only force fullscreen after returning from PiP if media playback has ended, but will keep fullscreen for playing/paused media. Differential Revision: https://phabricator.services.mozilla.com/D19750 --HG-- extra : moz-landing-system : lando --- .../java/org/mozilla/gecko/BrowserApp.java | 11 +++-- .../media/PictureInPictureController.java | 48 ++++++++++++++++--- 2 files changed, 48 insertions(+), 11 deletions(-) diff --git a/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java b/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java index e9a5833c92cc..5ec443f58da4 100644 --- a/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java +++ b/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java @@ -1083,11 +1083,14 @@ public class BrowserApp extends GeckoApp // by checking if the activity received onStop() or not. final boolean userReturnedToFullApp = !isApplicationInBackground(); - // After returning from Picture-in-picture mode the video will still be playing + // After returning from Picture-in-picture mode the video can still be playing // in fullscreen. But now we have the status bar showing. - // Call setFullscreen(..) to hide it and offer the same fullscreen video experience - // that the user had before entering in Picture-in-picture mode. - if (userReturnedToFullApp) { + // If media is still playing / is paused we need to call setFullscreen(..) to hide + // the status bar and offer the same fullscreen video experience that the user had + // before entering in Picture-in-picture mode. + final boolean shouldKeepVideoInFullscreen = + mPipController.isMediaPlaying() || mPipController.isMediaPaused(); + if (userReturnedToFullApp && shouldKeepVideoInFullscreen) { ActivityUtils.setFullScreen(this, true); } else { // User closed the PIP mode. diff --git a/mobile/android/base/java/org/mozilla/gecko/media/PictureInPictureController.java b/mobile/android/base/java/org/mozilla/gecko/media/PictureInPictureController.java index b41b458adf73..2d531ef98c80 100644 --- a/mobile/android/base/java/org/mozilla/gecko/media/PictureInPictureController.java +++ b/mobile/android/base/java/org/mozilla/gecko/media/PictureInPictureController.java @@ -18,6 +18,8 @@ import org.mozilla.gecko.AppConstants; import org.mozilla.gecko.BuildConfig; import org.mozilla.gecko.EventDispatcher; import org.mozilla.gecko.R; +import org.mozilla.gecko.Tab; +import org.mozilla.gecko.Tabs; import org.mozilla.gecko.util.ActivityUtils; import org.mozilla.gecko.util.BundleEventListener; import org.mozilla.gecko.util.EventCallback; @@ -32,6 +34,12 @@ public class PictureInPictureController implements BundleEventListener { private final Activity pipActivity; private boolean isInPipMode; + private PlaybackState playbackState = PlaybackState.STOPPED; + private enum PlaybackState { + PLAYING, + PAUSED, + STOPPED + } public PictureInPictureController(Activity activity) { pipActivity = activity; @@ -44,7 +52,7 @@ public class PictureInPictureController implements BundleEventListener { */ public void tryEnteringPictureInPictureMode() throws IllegalStateException { if (shouldTryPipMode() && - pipActivity.enterPictureInPictureMode(getPipParams(isMediaPlaying()))) { + pipActivity.enterPictureInPictureMode(getPipParams(isMediaPlayingForCurrentTab()))) { EventDispatcher.getInstance().registerUiThreadListener(this, "MediaControlService:MediaPlayingStatus"); isInPipMode = true; } @@ -61,6 +69,18 @@ public class PictureInPictureController implements BundleEventListener { return isInPipMode; } + public boolean isMediaPlaying() { + return playbackState == PlaybackState.PLAYING; + } + + public boolean isMediaPaused() { + return playbackState == PlaybackState.PAUSED; + } + + public boolean isMediaStopped() { + return playbackState == PlaybackState.STOPPED; + } + private boolean shouldTryPipMode() { if (!AppConstants.Versions.feature26Plus) { logDebugMessage("Picture In Picture is only available on Oreo+"); @@ -93,7 +113,7 @@ public class PictureInPictureController implements BundleEventListener { return false; } - if (!isMediaPlaying()) { + if (!isMediaPlayingForCurrentTab()) { logDebugMessage("Will not enter Picture in Picture mode if no media is playing"); return false; } @@ -157,8 +177,10 @@ public class PictureInPictureController implements BundleEventListener { return new Intent(action, null, pipActivity, MediaControlService.class); } - private boolean isMediaPlaying() { - return GeckoMediaControlAgent.isMediaPlaying(); + private boolean isMediaPlayingForCurrentTab() { + final Tab currentTab = Tabs.getInstance().getSelectedTab(); + + return currentTab != null && currentTab.isMediaPlaying(); } /** @@ -193,15 +215,27 @@ public class PictureInPictureController implements BundleEventListener { Log.w(LOGTAG, "Can't extract new media status"); return; } + + // Best hope scenario: we received this events for the current tab, for which we may allow PiP + // We check against `isMediaPlayingForCurrentTab()` to be sure. switch (newMediaStatus) { case "resumeMedia": - updatePictureInPictureActions(getPipParams(true)); + if (isMediaPlayingForCurrentTab()) { + updatePictureInPictureActions(getPipParams(true)); + playbackState = PlaybackState.PLAYING; + } break; case "mediaControlPaused": - updatePictureInPictureActions(getPipParams(false)); + if (!isMediaPlayingForCurrentTab()) { + updatePictureInPictureActions(getPipParams(false)); + playbackState = PlaybackState.PAUSED; + } break; case "mediaControlStopped": - updatePictureInPictureActions(getPipParams(false)); + if (!isMediaPlayingForCurrentTab()) { + updatePictureInPictureActions(getPipParams(false)); + playbackState = PlaybackState.STOPPED; + } break; default: Log.w(LOGTAG, String.format("Unknown new media status: %s", newMediaStatus));