Commit a1dc3684 authored by Jinsuk Kim's avatar Jinsuk Kim Committed by Commit Bot

Android: Move remaining fullscreen tasks to FullscreenHtmlApiHandler

This CL moves the remaining fullscreen enter/exit-related tasks to
FullscreenHtmlApiHandler. ChromeFullscreenManager is still the
receiver of the requests but simply relays the call to the handler.

Added another method |onEnterFullscreen| FullscreenManager
interface. This is used by TabWebContentsDelegateAndroid to process
the fullscreen initiation flow.

Follow-up CL will split ChromeFullscreenManager and route the
initiation/termination flow directly to the handler.

Bug: 966272
Change-Id: I86b3ad0ee027cde26144469a262737711825cd15
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2245170
Commit-Queue: Jinsuk Kim <jinsukkim@chromium.org>
Reviewed-by: default avatarMatthew Jones <mdjones@chromium.org>
Reviewed-by: default avatarTheresa  <twellington@chromium.org>
Cr-Commit-Position: refs/heads/master@{#779628}
parent 7a647232
...@@ -30,6 +30,7 @@ import org.chromium.chrome.browser.document.ChromeIntentUtil; ...@@ -30,6 +30,7 @@ import org.chromium.chrome.browser.document.ChromeIntentUtil;
import org.chromium.chrome.browser.document.DocumentWebContentsDelegate; import org.chromium.chrome.browser.document.DocumentWebContentsDelegate;
import org.chromium.chrome.browser.fullscreen.BrowserControlsStateProvider; import org.chromium.chrome.browser.fullscreen.BrowserControlsStateProvider;
import org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager; import org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager;
import org.chromium.chrome.browser.fullscreen.FullscreenManager;
import org.chromium.chrome.browser.fullscreen.FullscreenOptions; import org.chromium.chrome.browser.fullscreen.FullscreenOptions;
import org.chromium.chrome.browser.media.PictureInPicture; import org.chromium.chrome.browser.media.PictureInPicture;
import org.chromium.chrome.browser.policy.PolicyAuditor; import org.chromium.chrome.browser.policy.PolicyAuditor;
...@@ -126,7 +127,7 @@ public class ActivityTabWebContentsDelegateAndroid extends TabWebContentsDelegat ...@@ -126,7 +127,7 @@ public class ActivityTabWebContentsDelegateAndroid extends TabWebContentsDelegat
@Override @Override
public boolean isFullscreenForTabOrPending() { public boolean isFullscreenForTabOrPending() {
ChromeFullscreenManager manager = getFullscreenManager(); FullscreenManager manager = getFullscreenManager();
return manager != null ? manager.getPersistentFullscreenMode() : false; return manager != null ? manager.getPersistentFullscreenMode() : false;
} }
...@@ -336,13 +337,13 @@ public class ActivityTabWebContentsDelegateAndroid extends TabWebContentsDelegat ...@@ -336,13 +337,13 @@ public class ActivityTabWebContentsDelegateAndroid extends TabWebContentsDelegat
@Override @Override
public boolean controlsResizeView() { public boolean controlsResizeView() {
ChromeFullscreenManager manager = getFullscreenManager(); return mActivity != null && mActivity.getCompositorViewHolder() != null
return manager != null ? manager.controlsResizeView() : false; && mActivity.getCompositorViewHolder().controlsResizeView();
} }
@Override @Override
public void enterFullscreenModeForTab(boolean prefersNavigationBar) { public void enterFullscreenModeForTab(boolean prefersNavigationBar) {
ChromeFullscreenManager manager = getFullscreenManager(); FullscreenManager manager = getFullscreenManager();
if (manager != null) { if (manager != null) {
manager.onEnterFullscreen(mTab, new FullscreenOptions(prefersNavigationBar)); manager.onEnterFullscreen(mTab, new FullscreenOptions(prefersNavigationBar));
} }
...@@ -350,7 +351,7 @@ public class ActivityTabWebContentsDelegateAndroid extends TabWebContentsDelegat ...@@ -350,7 +351,7 @@ public class ActivityTabWebContentsDelegateAndroid extends TabWebContentsDelegat
@Override @Override
public void exitFullscreenModeForTab() { public void exitFullscreenModeForTab() {
ChromeFullscreenManager manager = getFullscreenManager(); FullscreenManager manager = getFullscreenManager();
if (manager != null) manager.onExitFullscreen(mTab); if (manager != null) manager.onExitFullscreen(mTab);
} }
......
...@@ -48,6 +48,7 @@ import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager; ...@@ -48,6 +48,7 @@ import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager;
import org.chromium.chrome.browser.contextualsearch.ContextualSearchManagementDelegate; import org.chromium.chrome.browser.contextualsearch.ContextualSearchManagementDelegate;
import org.chromium.chrome.browser.device.DeviceClassManager; import org.chromium.chrome.browser.device.DeviceClassManager;
import org.chromium.chrome.browser.fullscreen.BrowserControlsStateProvider; import org.chromium.chrome.browser.fullscreen.BrowserControlsStateProvider;
import org.chromium.chrome.browser.fullscreen.BrowserControlsUtils;
import org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager; import org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager;
import org.chromium.chrome.browser.tab.EmptyTabObserver; import org.chromium.chrome.browser.tab.EmptyTabObserver;
import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.Tab;
...@@ -163,6 +164,8 @@ public class CompositorViewHolder extends FrameLayout ...@@ -163,6 +164,8 @@ public class CompositorViewHolder extends FrameLayout
private boolean mIsInVr; private boolean mIsInVr;
private boolean mControlsResizeView;
// Indicates if ContentCaptureConsumer should be created, we only try to create it once. // Indicates if ContentCaptureConsumer should be created, we only try to create it once.
private boolean mShouldCreateContentCaptureConsumer = true; private boolean mShouldCreateContentCaptureConsumer = true;
private ContentCaptureConsumer mContentCaptureConsumer; private ContentCaptureConsumer mContentCaptureConsumer;
...@@ -721,7 +724,7 @@ public class CompositorViewHolder extends FrameLayout ...@@ -721,7 +724,7 @@ public class CompositorViewHolder extends FrameLayout
? mFullscreenManager.getTopControlsMinHeight() ? mFullscreenManager.getTopControlsMinHeight()
+ mFullscreenManager.getBottomControlsMinHeight() + mFullscreenManager.getBottomControlsMinHeight()
: 0; : 0;
int controlsHeight = controlsResizeView() int controlsHeight = mControlsResizeView
? getTopControlsHeightPixels() + getBottomControlsHeightPixels() ? getTopControlsHeightPixels() + getBottomControlsHeightPixels()
: totalMinHeight; : totalMinHeight;
...@@ -811,6 +814,9 @@ public class CompositorViewHolder extends FrameLayout ...@@ -811,6 +814,9 @@ public class CompositorViewHolder extends FrameLayout
} }
private void onUpdateViewportSize() { private void onUpdateViewportSize() {
if (mFullscreenManager != null) {
mControlsResizeView = BrowserControlsUtils.controlsResizeView(mFullscreenManager);
}
// Reflect the changes that may have happened in in view/control size. // Reflect the changes that may have happened in in view/control size.
Point viewportSize = getViewportSize(); Point viewportSize = getViewportSize();
setSize(getWebContents(), getContentView(), viewportSize.x, viewportSize.y); setSize(getWebContents(), getContentView(), viewportSize.x, viewportSize.y);
...@@ -1021,7 +1027,7 @@ public class CompositorViewHolder extends FrameLayout ...@@ -1021,7 +1027,7 @@ public class CompositorViewHolder extends FrameLayout
* @return {@code true} if browser controls shrink Blink view's size. * @return {@code true} if browser controls shrink Blink view's size.
*/ */
public boolean controlsResizeView() { public boolean controlsResizeView() {
return mFullscreenManager != null && mFullscreenManager.controlsResizeView(); return mControlsResizeView;
} }
@Override @Override
......
...@@ -29,4 +29,24 @@ public class BrowserControlsUtils { ...@@ -29,4 +29,24 @@ public class BrowserControlsUtils {
public static boolean drawControlsAsTexture(BrowserControlsStateProvider stateProvider) { public static boolean drawControlsAsTexture(BrowserControlsStateProvider stateProvider) {
return stateProvider.getBrowserControlHiddenRatio() > 0; return stateProvider.getBrowserControlHiddenRatio() > 0;
} }
/**
* TODO(jinsukkim): Move this to CompositorViewHolder.
* @return {@code true} if browser controls shrink Blink view's size. Note that this
* is valid only when the browser controls are in idle state i.e. not scrolling
* or animating.
*/
public static boolean controlsResizeView(BrowserControlsStateProvider stateProvider) {
return stateProvider.getContentOffset() > stateProvider.getTopControlsMinHeight()
|| getBottomContentOffset(stateProvider)
> stateProvider.getBottomControlsMinHeight();
}
/**
* @return The content offset from the bottom of the screen, or the visible height of the bottom
* controls, in px.
*/
public static int getBottomContentOffset(BrowserControlsStateProvider stateProvider) {
return stateProvider.getBottomControlsHeight() - stateProvider.getBottomControlOffset();
}
} }
...@@ -22,10 +22,8 @@ import androidx.annotation.VisibleForTesting; ...@@ -22,10 +22,8 @@ import androidx.annotation.VisibleForTesting;
import org.chromium.base.ActivityState; import org.chromium.base.ActivityState;
import org.chromium.base.ApplicationStatus; import org.chromium.base.ApplicationStatus;
import org.chromium.base.ApplicationStatus.ActivityStateListener; import org.chromium.base.ApplicationStatus.ActivityStateListener;
import org.chromium.base.ApplicationStatus.WindowFocusChangedListener;
import org.chromium.base.ObserverList; import org.chromium.base.ObserverList;
import org.chromium.base.TraceEvent; import org.chromium.base.TraceEvent;
import org.chromium.base.library_loader.LibraryLoader;
import org.chromium.base.supplier.ObservableSupplierImpl; import org.chromium.base.supplier.ObservableSupplierImpl;
import org.chromium.base.task.PostTask; import org.chromium.base.task.PostTask;
import org.chromium.chrome.browser.ActivityTabProvider; import org.chromium.chrome.browser.ActivityTabProvider;
...@@ -33,11 +31,8 @@ import org.chromium.chrome.browser.ActivityTabProvider.ActivityTabTabObserver; ...@@ -33,11 +31,8 @@ import org.chromium.chrome.browser.ActivityTabProvider.ActivityTabTabObserver;
import org.chromium.chrome.browser.ChromeActivity; import org.chromium.chrome.browser.ChromeActivity;
import org.chromium.chrome.browser.tab.SadTab; import org.chromium.chrome.browser.tab.SadTab;
import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tab.TabAttributeKeys;
import org.chromium.chrome.browser.tab.TabAttributes;
import org.chromium.chrome.browser.tab.TabBrowserControlsConstraintsHelper; import org.chromium.chrome.browser.tab.TabBrowserControlsConstraintsHelper;
import org.chromium.chrome.browser.tab.TabBrowserControlsOffsetHelper; import org.chromium.chrome.browser.tab.TabBrowserControlsOffsetHelper;
import org.chromium.chrome.browser.tab.TabHidingType;
import org.chromium.chrome.browser.tabmodel.TabModelImpl; import org.chromium.chrome.browser.tabmodel.TabModelImpl;
import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.browser.tabmodel.TabModelSelector;
import org.chromium.chrome.browser.tabmodel.TabModelSelectorTabObserver; import org.chromium.chrome.browser.tabmodel.TabModelSelectorTabObserver;
...@@ -45,26 +40,20 @@ import org.chromium.chrome.browser.toolbar.ControlContainer; ...@@ -45,26 +40,20 @@ import org.chromium.chrome.browser.toolbar.ControlContainer;
import org.chromium.chrome.browser.vr.VrModuleProvider; import org.chromium.chrome.browser.vr.VrModuleProvider;
import org.chromium.components.browser_ui.util.BrowserControlsVisibilityDelegate; import org.chromium.components.browser_ui.util.BrowserControlsVisibilityDelegate;
import org.chromium.components.embedder_support.view.ContentView; import org.chromium.components.embedder_support.view.ContentView;
import org.chromium.content_public.browser.GestureListenerManager;
import org.chromium.content_public.browser.NavigationHandle;
import org.chromium.content_public.browser.SelectionPopupController;
import org.chromium.content_public.browser.UiThreadTaskTraits; import org.chromium.content_public.browser.UiThreadTaskTraits;
import org.chromium.content_public.browser.WebContents;
import org.chromium.content_public.common.BrowserControlsState; import org.chromium.content_public.common.BrowserControlsState;
import org.chromium.ui.util.TokenHolder; import org.chromium.ui.util.TokenHolder;
import org.chromium.ui.vr.VrModeObserver; import org.chromium.ui.vr.VrModeObserver;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
/** /**
* A class that manages control and content views to create the fullscreen mode. * A class that manages control and content views to create the fullscreen mode.
*/ */
public class ChromeFullscreenManager public class ChromeFullscreenManager implements ActivityStateListener,
implements ActivityStateListener, WindowFocusChangedListener, ViewGroup.OnHierarchyChangeListener, VrModeObserver,
ViewGroup.OnHierarchyChangeListener, View.OnSystemUiVisibilityChangeListener, BrowserControlsSizer, FullscreenManager {
VrModeObserver, BrowserControlsSizer, FullscreenManager {
// The amount of time to delay the control show request after returning to a once visible // The amount of time to delay the control show request after returning to a once visible
// activity. This delay is meant to allow Android to run its Activity focusing animation and // activity. This delay is meant to allow Android to run its Activity focusing animation and
// have the controls scroll back in smoothly once that has finished. // have the controls scroll back in smoothly once that has finished.
...@@ -79,7 +68,6 @@ public class ChromeFullscreenManager ...@@ -79,7 +68,6 @@ public class ChromeFullscreenManager
private final Activity mActivity; private final Activity mActivity;
private final BrowserStateBrowserControlsVisibilityDelegate mBrowserVisibilityDelegate; private final BrowserStateBrowserControlsVisibilityDelegate mBrowserVisibilityDelegate;
@ControlsPosition private final int mControlsPosition; @ControlsPosition private final int mControlsPosition;
private final boolean mExitFullscreenOnStop;
private final TokenHolder mHidingTokenHolder = new TokenHolder(this::scheduleVisibilityUpdate); private final TokenHolder mHidingTokenHolder = new TokenHolder(this::scheduleVisibilityUpdate);
/** /**
...@@ -89,14 +77,13 @@ public class ChromeFullscreenManager ...@@ -89,14 +77,13 @@ public class ChromeFullscreenManager
private final ObservableSupplierImpl<Boolean> mControlsAtMinHeight = private final ObservableSupplierImpl<Boolean> mControlsAtMinHeight =
new ObservableSupplierImpl<>(); new ObservableSupplierImpl<>();
private TabModelSelectorTabObserver mTabFullscreenObserver; private TabModelSelectorTabObserver mTabControlsObserver;
@Nullable private ControlContainer mControlContainer; @Nullable private ControlContainer mControlContainer;
private int mTopControlContainerHeight; private int mTopControlContainerHeight;
private int mTopControlsMinHeight; private int mTopControlsMinHeight;
private int mBottomControlContainerHeight; private int mBottomControlContainerHeight;
private int mBottomControlsMinHeight; private int mBottomControlsMinHeight;
private boolean mAnimateBrowserControlsHeightChanges; private boolean mAnimateBrowserControlsHeightChanges;
private boolean mControlsResizeView;
private int mRendererTopControlOffset; private int mRendererTopControlOffset;
private int mRendererBottomControlOffset; private int mRendererBottomControlOffset;
...@@ -115,7 +102,6 @@ public class ChromeFullscreenManager ...@@ -115,7 +102,6 @@ public class ChromeFullscreenManager
// in the current Tab. // in the current Tab.
private ContentView mContentView; private ContentView mContentView;
private final ArrayList<FullscreenManager.Observer> mFullscreenObservers = new ArrayList<>();
private final ObserverList<BrowserControlsStateProvider.Observer> mControlsObservers = private final ObserverList<BrowserControlsStateProvider.Observer> mControlsObservers =
new ObserverList<>(); new ObserverList<>();
private Runnable mViewportSizeDelegate; private Runnable mViewportSizeDelegate;
...@@ -178,10 +164,9 @@ public class ChromeFullscreenManager ...@@ -178,10 +164,9 @@ public class ChromeFullscreenManager
@ControlsPosition int controlsPosition, boolean exitFullscreenOnStop) { @ControlsPosition int controlsPosition, boolean exitFullscreenOnStop) {
mActivity = activity; mActivity = activity;
mControlsPosition = controlsPosition; mControlsPosition = controlsPosition;
mExitFullscreenOnStop = exitFullscreenOnStop;
mControlsAtMinHeight.set(false); mControlsAtMinHeight.set(false);
mHtmlApiHandler = new FullscreenHtmlApiHandler(activity.getWindow(), this::getTab, mHtmlApiHandler = new FullscreenHtmlApiHandler(activity, mControlsAtMinHeight,
mControlsAtMinHeight, () -> !(isInVr() || bootsToVr())); () -> !(isInVr() || bootsToVr()), exitFullscreenOnStop);
mBrowserVisibilityDelegate = new BrowserStateBrowserControlsVisibilityDelegate( mBrowserVisibilityDelegate = new BrowserStateBrowserControlsVisibilityDelegate(
mHtmlApiHandler.getPersistentFullscreenModeSupplier()); mHtmlApiHandler.getPersistentFullscreenModeSupplier());
mBrowserVisibilityDelegate.addObserver((constraints) -> { mBrowserVisibilityDelegate.addObserver((constraints) -> {
...@@ -202,8 +187,8 @@ public class ChromeFullscreenManager ...@@ -202,8 +187,8 @@ public class ChromeFullscreenManager
public void initialize(ControlContainer controlContainer, public void initialize(ControlContainer controlContainer,
ActivityTabProvider activityTabProvider, final TabModelSelector modelSelector, ActivityTabProvider activityTabProvider, final TabModelSelector modelSelector,
int resControlContainerHeight) { int resControlContainerHeight) {
mHtmlApiHandler.initialize(activityTabProvider, modelSelector);
ApplicationStatus.registerStateListenerForActivity(this, mActivity); ApplicationStatus.registerStateListenerForActivity(this, mActivity);
ApplicationStatus.registerWindowFocusChangedListener(this);
mActiveTabObserver = new ActivityTabTabObserver(activityTabProvider) { mActiveTabObserver = new ActivityTabTabObserver(activityTabProvider) {
@Override @Override
protected void onObservingDifferentTab(Tab tab) { protected void onObservingDifferentTab(Tab tab) {
...@@ -217,40 +202,21 @@ public class ChromeFullscreenManager ...@@ -217,40 +202,21 @@ public class ChromeFullscreenManager
} }
}; };
mTabFullscreenObserver = new TabModelSelectorTabObserver(modelSelector) { mTabControlsObserver = new TabModelSelectorTabObserver(modelSelector) {
@Override
public void onHidden(Tab tab, @TabHidingType int reason) {
// Clean up any fullscreen state that might impact other tabs.
exitPersistentFullscreenMode();
}
@Override @Override
public void onContentChanged(Tab tab) { public void onContentChanged(Tab tab) {
if (tab == getTab()) updateViewStateListener(); if (tab == getTab()) updateViewStateListener();
} }
@Override
public void onDidFinishNavigation(Tab tab, NavigationHandle navigation) {
if (navigation.isInMainFrame() && !navigation.isSameDocument()) {
if (tab == getTab()) exitPersistentFullscreenMode();
}
}
@Override @Override
public void onInteractabilityChanged(Tab tab, boolean interactable) { public void onInteractabilityChanged(Tab tab, boolean interactable) {
Tab currentTab = getTab(); if (!interactable || tab != getTab()) return;
if (!interactable || tab != currentTab) return; TabBrowserControlsOffsetHelper helper = TabBrowserControlsOffsetHelper.get(tab);
Runnable enterFullscreen = getEnterFullscreenRunnable(currentTab); if (!helper.offsetInitialized()) return;
if (enterFullscreen != null) enterFullscreen.run();
onOffsetsChanged(helper.topControlsOffset(), helper.bottomControlsOffset(),
TabBrowserControlsOffsetHelper offsetHelper = helper.contentOffset(), helper.topControlsMinHeightOffset(),
TabBrowserControlsOffsetHelper.get(currentTab); helper.bottomControlsMinHeightOffset());
if (!offsetHelper.offsetInitialized()) return;
onOffsetsChanged(offsetHelper.topControlsOffset(),
offsetHelper.bottomControlsOffset(), offsetHelper.contentOffset(),
offsetHelper.topControlsMinHeightOffset(),
offsetHelper.bottomControlsMinHeightOffset());
} }
@Override @Override
...@@ -314,7 +280,6 @@ public class ChromeFullscreenManager ...@@ -314,7 +280,6 @@ public class ChromeFullscreenManager
updateViewStateListener(); updateViewStateListener();
if (tab != null) { if (tab != null) {
mBrowserVisibilityDelegate.showControlsTransient(); mBrowserVisibilityDelegate.showControlsTransient();
updateMultiTouchZoomSupport(!getPersistentFullscreenMode());
if (tab.isUserInteractable()) restoreControlsPositions(); if (tab.isUserInteractable()) restoreControlsPositions();
} }
} }
...@@ -324,66 +289,21 @@ public class ChromeFullscreenManager ...@@ -324,66 +289,21 @@ public class ChromeFullscreenManager
} }
} }
/** // FullscreenManager
* Enter fullscreen.
* @param tab {@link Tab} that goes into fullscreen.
* @param options Fullscreen options.
*/
public void onEnterFullscreen(Tab tab, FullscreenOptions options) {
// If enabling fullscreen while the tab is not interactable, fullscreen
// will be delayed until the tab is interactable.
Runnable r = () -> {
enterPersistentFullscreenMode(options);
destroySelectActionMode(tab);
setEnterFullscreenRunnable(tab, null);
};
if (tab.isUserInteractable()) { @Override
r.run(); public void onEnterFullscreen(Tab tab, FullscreenOptions options) {
} else { mHtmlApiHandler.onEnterFullscreen(tab, options);
setEnterFullscreenRunnable(tab, r);
}
for (FullscreenManager.Observer observer : mFullscreenObservers) {
observer.onEnterFullscreen(tab, options);
}
} }
@Override @Override
public void onExitFullscreen(Tab tab) { public void onExitFullscreen(Tab tab) {
setEnterFullscreenRunnable(tab, null); mHtmlApiHandler.onExitFullscreen(tab);
if (tab == getTab()) exitPersistentFullscreenMode();
for (FullscreenManager.Observer observer : mFullscreenObservers) {
observer.onExitFullscreen(tab);
}
}
/**
* Enters persistent fullscreen mode. In this mode, the browser controls will be
* permanently hidden until this mode is exited.
*/
private void enterPersistentFullscreenMode(FullscreenOptions options) {
mHtmlApiHandler.enterPersistentFullscreenMode(options);
updateMultiTouchZoomSupport(false);
} }
@Override @Override
public void exitPersistentFullscreenMode() { public void exitPersistentFullscreenMode() {
mHtmlApiHandler.exitPersistentFullscreenMode(); mHtmlApiHandler.exitPersistentFullscreenMode();
updateMultiTouchZoomSupport(true);
}
/**
* @see GestureListenerManager#updateMultiTouchZoomSupport(boolean).
*/
private void updateMultiTouchZoomSupport(boolean enable) {
Tab tab = getTab();
if (tab == null || tab.isHidden()) return;
WebContents webContents = tab.getWebContents();
if (webContents != null) {
GestureListenerManager manager = GestureListenerManager.fromWebContents(webContents);
if (manager != null) manager.updateMultiTouchZoomSupport(enable);
}
} }
@Override @Override
...@@ -391,73 +311,29 @@ public class ChromeFullscreenManager ...@@ -391,73 +311,29 @@ public class ChromeFullscreenManager
return mHtmlApiHandler.getPersistentFullscreenMode(); return mHtmlApiHandler.getPersistentFullscreenMode();
} }
/**
* Notified when the system UI visibility for the current ContentView has changed.
* @param visibility The updated UI visibility.
* @see View#getSystemUiVisibility()
*/
public void onContentViewSystemUiVisibilityChange(int visibility) {
mHtmlApiHandler.onContentViewSystemUiVisibilityChange(visibility);
}
private void destroySelectActionMode(Tab tab) {
WebContents webContents = tab.getWebContents();
if (webContents != null) {
SelectionPopupController.fromWebContents(webContents).destroySelectActionMode();
}
}
private void setEnterFullscreenRunnable(Tab tab, Runnable runnable) {
TabAttributes attrs = TabAttributes.from(tab);
if (runnable == null) {
attrs.clear(TabAttributeKeys.ENTER_FULLSCREEN);
} else {
attrs.set(TabAttributeKeys.ENTER_FULLSCREEN, runnable);
}
}
private Runnable getEnterFullscreenRunnable(Tab tab) {
return tab != null ? TabAttributes.from(tab).get(TabAttributeKeys.ENTER_FULLSCREEN) : null;
}
private void updateViewStateListener() { private void updateViewStateListener() {
if (mContentView != null) { if (mContentView != null) {
mContentView.removeOnHierarchyChangeListener(this); mContentView.removeOnHierarchyChangeListener(this);
mContentView.removeOnSystemUiVisibilityChangeListener(this);
} }
mContentView = getContentView(); mContentView = getContentView();
if (mContentView != null) { if (mContentView != null) {
mContentView.addOnHierarchyChangeListener(this); mContentView.addOnHierarchyChangeListener(this);
mContentView.addOnSystemUiVisibilityChangeListener(this);
} }
} }
// ActivityStateListener
@Override @Override
public void onActivityStateChange(Activity activity, int newState) { public void onActivityStateChange(Activity activity, int newState) {
if (newState == ActivityState.STOPPED && mExitFullscreenOnStop) { if (newState == ActivityState.STARTED) {
// Exit fullscreen in onStop to ensure the system UI flags are set correctly when
// showing again (on JB MR2+ builds, the omnibox would be covered by the
// notification bar when this was done in onStart()).
exitPersistentFullscreenMode();
} else if (newState == ActivityState.STARTED) {
PostTask.postDelayedTask(UiThreadTaskTraits.DEFAULT, PostTask.postDelayedTask(UiThreadTaskTraits.DEFAULT,
() mBrowserVisibilityDelegate::showControlsTransient,
-> mBrowserVisibilityDelegate.showControlsTransient(),
ACTIVITY_RETURN_SHOW_REQUEST_DELAY_MS); ACTIVITY_RETURN_SHOW_REQUEST_DELAY_MS);
} else if (newState == ActivityState.DESTROYED) { } else if (newState == ActivityState.DESTROYED) {
ApplicationStatus.unregisterActivityStateListener(this); ApplicationStatus.unregisterActivityStateListener(this);
ApplicationStatus.unregisterWindowFocusChangedListener(this);
} }
} }
@Override
public void onWindowFocusChanged(Activity activity, boolean hasFocus) {
if (mActivity != activity) return;
mHtmlApiHandler.onWindowFocusChanged(hasFocus);
// {@link ContentVideoView#getContentVideoView} requires native to have been initialized.
if (!LibraryLoader.getInstance().isInitialized()) return;
}
@Override @Override
public float getBrowserControlHiddenRatio() { public float getBrowserControlHiddenRatio() {
return mControlOffsetRatio; return mControlOffsetRatio;
...@@ -532,10 +408,6 @@ public class ChromeFullscreenManager ...@@ -532,10 +408,6 @@ public class ChromeFullscreenManager
return mAnimateBrowserControlsHeightChanges; return mAnimateBrowserControlsHeightChanges;
} }
public boolean controlsResizeView() {
return mControlsResizeView;
}
@Override @Override
public int getContentOffset() { public int getContentOffset() {
return mRendererTopContentOffset; return mRendererTopContentOffset;
...@@ -551,12 +423,8 @@ public class ChromeFullscreenManager ...@@ -551,12 +423,8 @@ public class ChromeFullscreenManager
return mRendererTopControlsMinHeightOffset; return mRendererTopControlsMinHeightOffset;
} }
/** private int getBottomContentOffset() {
* @return The content offset from the bottom of the screen, or the visible height of the bottom return BrowserControlsUtils.getBottomContentOffset(this);
* controls, in px.
*/
public int getBottomContentOffset() {
return getBottomControlsHeight() - getBottomControlOffset();
} }
@Override @Override
...@@ -601,12 +469,12 @@ public class ChromeFullscreenManager ...@@ -601,12 +469,12 @@ public class ChromeFullscreenManager
@Override @Override
public void addObserver(FullscreenManager.Observer observer) { public void addObserver(FullscreenManager.Observer observer) {
if (!mFullscreenObservers.contains(observer)) mFullscreenObservers.add(observer); mHtmlApiHandler.addObserver(observer);
} }
@Override @Override
public void removeObserver(FullscreenManager.Observer observer) { public void removeObserver(FullscreenManager.Observer observer) {
mFullscreenObservers.remove(observer); mHtmlApiHandler.removeObserver(observer);
} }
/** /**
...@@ -626,8 +494,6 @@ public class ChromeFullscreenManager ...@@ -626,8 +494,6 @@ public class ChromeFullscreenManager
// scrolling or animating. // scrolling or animating.
if (!areBrowserControlsIdle()) return; if (!areBrowserControlsIdle()) return;
mControlsResizeView = getContentOffset() > getTopControlsMinHeight()
|| getBottomContentOffset() > getBottomControlsMinHeight();
if (mViewportSizeDelegate != null) mViewportSizeDelegate.run(); if (mViewportSizeDelegate != null) mViewportSizeDelegate.run();
} }
...@@ -668,11 +534,6 @@ public class ChromeFullscreenManager ...@@ -668,11 +534,6 @@ public class ChromeFullscreenManager
updateViewportSize(); updateViewportSize();
} }
@Override
public void onSystemUiVisibilityChange(int visibility) {
onContentViewSystemUiVisibilityChange(visibility);
}
/** /**
* Utility routine for ensuring visibility updates are synchronized with * Utility routine for ensuring visibility updates are synchronized with
* animation, preventing message loop stalls due to untimely invalidation. * animation, preventing message loop stalls due to untimely invalidation.
...@@ -1078,18 +939,18 @@ public class ChromeFullscreenManager ...@@ -1078,18 +939,18 @@ public class ChromeFullscreenManager
*/ */
public void destroy() { public void destroy() {
mTab = null; mTab = null;
mHtmlApiHandler.destroy();
if (mActiveTabObserver != null) mActiveTabObserver.destroy(); if (mActiveTabObserver != null) mActiveTabObserver.destroy();
mBrowserVisibilityDelegate.destroy(); mBrowserVisibilityDelegate.destroy();
if (mTabFullscreenObserver != null) mTabFullscreenObserver.destroy(); if (mTabControlsObserver != null) mTabControlsObserver.destroy();
if (mContentView != null) { if (mContentView != null) {
mContentView.removeOnHierarchyChangeListener(this); mContentView.removeOnHierarchyChangeListener(this);
mContentView.removeOnSystemUiVisibilityChangeListener(this);
} }
VrModuleProvider.unregisterVrModeObserver(this); VrModuleProvider.unregisterVrModeObserver(this);
} }
@VisibleForTesting @VisibleForTesting
TabModelSelectorTabObserver getTabFullscreenObserverForTesting() { TabModelSelectorTabObserver getTabControlsObserverForTesting() {
return mTabFullscreenObserver; return mTabControlsObserver;
} }
} }
...@@ -20,14 +20,30 @@ import android.view.WindowManager; ...@@ -20,14 +20,30 @@ import android.view.WindowManager;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.core.util.ObjectsCompat; import androidx.core.util.ObjectsCompat;
import org.chromium.base.ActivityState;
import org.chromium.base.ApplicationStatus;
import org.chromium.base.ApplicationStatus.ActivityStateListener;
import org.chromium.base.ApplicationStatus.WindowFocusChangedListener;
import org.chromium.base.ObserverList;
import org.chromium.base.supplier.ObservableSupplier; import org.chromium.base.supplier.ObservableSupplier;
import org.chromium.base.supplier.ObservableSupplierImpl; import org.chromium.base.supplier.ObservableSupplierImpl;
import org.chromium.base.supplier.Supplier; import org.chromium.base.supplier.Supplier;
import org.chromium.chrome.R; import org.chromium.chrome.R;
import org.chromium.chrome.browser.ActivityTabProvider;
import org.chromium.chrome.browser.ActivityTabProvider.ActivityTabTabObserver;
import org.chromium.chrome.browser.multiwindow.MultiWindowUtils; import org.chromium.chrome.browser.multiwindow.MultiWindowUtils;
import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tab.TabAttributeKeys;
import org.chromium.chrome.browser.tab.TabAttributes;
import org.chromium.chrome.browser.tab.TabBrowserControlsConstraintsHelper; import org.chromium.chrome.browser.tab.TabBrowserControlsConstraintsHelper;
import org.chromium.chrome.browser.tab.TabHidingType;
import org.chromium.chrome.browser.tab.TabUtils; import org.chromium.chrome.browser.tab.TabUtils;
import org.chromium.chrome.browser.tabmodel.TabModelSelector;
import org.chromium.chrome.browser.tabmodel.TabModelSelectorTabObserver;
import org.chromium.components.embedder_support.view.ContentView;
import org.chromium.content_public.browser.GestureListenerManager;
import org.chromium.content_public.browser.NavigationHandle;
import org.chromium.content_public.browser.SelectionPopupController;
import org.chromium.content_public.browser.WebContents; import org.chromium.content_public.browser.WebContents;
import org.chromium.content_public.common.BrowserControlsState; import org.chromium.content_public.common.BrowserControlsState;
import org.chromium.ui.widget.Toast; import org.chromium.ui.widget.Toast;
...@@ -37,7 +53,9 @@ import java.lang.ref.WeakReference; ...@@ -37,7 +53,9 @@ import java.lang.ref.WeakReference;
/** /**
* Handles updating the UI based on requests to the HTML Fullscreen API. * Handles updating the UI based on requests to the HTML Fullscreen API.
*/ */
public class FullscreenHtmlApiHandler { public class FullscreenHtmlApiHandler implements ActivityStateListener, WindowFocusChangedListener,
View.OnSystemUiVisibilityChangeListener,
FullscreenManager {
private static final int MSG_ID_SET_FULLSCREEN_SYSTEM_UI_FLAGS = 1; private static final int MSG_ID_SET_FULLSCREEN_SYSTEM_UI_FLAGS = 1;
private static final int MSG_ID_CLEAR_LAYOUT_FULLSCREEN_FLAG = 2; private static final int MSG_ID_CLEAR_LAYOUT_FULLSCREEN_FLAG = 2;
...@@ -49,12 +67,13 @@ public class FullscreenHtmlApiHandler { ...@@ -49,12 +67,13 @@ public class FullscreenHtmlApiHandler {
// the SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN flag. // the SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN flag.
private static final long CLEAR_LAYOUT_FULLSCREEN_DELAY_MS = 20; private static final long CLEAR_LAYOUT_FULLSCREEN_DELAY_MS = 20;
private final Window mWindow; private final Activity mActivity;
private final Handler mHandler; private final Handler mHandler;
private final ObservableSupplierImpl<Boolean> mPersistentModeSupplier; private final ObservableSupplierImpl<Boolean> mPersistentModeSupplier;
private final Supplier<Tab> mCurrentTab;
private final ObservableSupplier<Boolean> mAreControlsHidden; private final ObservableSupplier<Boolean> mAreControlsHidden;
private final Supplier<Boolean> mShowToast; private final Supplier<Boolean> mShowToast;
private final boolean mExitFullscreenOnStop;
private final ObserverList<FullscreenManager.Observer> mObservers = new ObserverList<>();
// We need to cache WebContents/ContentView since we are setting fullscreen UI state on // We need to cache WebContents/ContentView since we are setting fullscreen UI state on
// the WebContents's container view, and a Tab can change to have null web contents/ // the WebContents's container view, and a Tab can change to have null web contents/
...@@ -74,6 +93,15 @@ public class FullscreenHtmlApiHandler { ...@@ -74,6 +93,15 @@ public class FullscreenHtmlApiHandler {
private FullscreenOptions mPendingFullscreenOptions; private FullscreenOptions mPendingFullscreenOptions;
private ActivityTabTabObserver mActiveTabObserver;
private TabModelSelectorTabObserver mTabFullscreenObserver;
@Nullable
private Tab mTab;
// Current ContentView. Updates when active tab is switched or WebContents is swapped
// in the current Tab.
private ContentView mContentView;
// This static inner class holds a WeakReference to the outer object, to avoid triggering the // This static inner class holds a WeakReference to the outer object, to avoid triggering the
// lint HandlerLeak warning. // lint HandlerLeak warning.
private static class FullscreenHandler extends Handler { private static class FullscreenHandler extends Handler {
...@@ -155,15 +183,16 @@ public class FullscreenHtmlApiHandler { ...@@ -155,15 +183,16 @@ public class FullscreenHtmlApiHandler {
/** /**
* Constructs the handler that will manage the UI transitions from the HTML fullscreen API. * Constructs the handler that will manage the UI transitions from the HTML fullscreen API.
* *
* @param window The window containing the view going to fullscreen. * @param activity The activity that supports fullscreen.
* @param currentTab Supplier of the current activity tab.
* @param areControlsHidden Supplier of a flag indicating if browser controls are hidden. * @param areControlsHidden Supplier of a flag indicating if browser controls are hidden.
* @param showToast Supplier of a flag indicating if toast message should be shown. * @param showToast Supplier of a flag indicating if toast message should be shown.
* @param exitFullscreenOnStop Whether fullscreen mode should exit on stop - should be
* true for Activities that are not always fullscreen.
*/ */
public FullscreenHtmlApiHandler(Window window, Supplier<Tab> currentTab, public FullscreenHtmlApiHandler(Activity activity,
ObservableSupplier<Boolean> areControlsHidden, Supplier<Boolean> showToast) { ObservableSupplier<Boolean> areControlsHidden, Supplier<Boolean> showToast,
mWindow = window; boolean exitFullscreenOnStop) {
mCurrentTab = currentTab; mActivity = activity;
mAreControlsHidden = areControlsHidden; mAreControlsHidden = areControlsHidden;
mAreControlsHidden.addObserver(this::maybeEnterFullscreenFromPendingState); mAreControlsHidden.addObserver(this::maybeEnterFullscreenFromPendingState);
mShowToast = showToast; mShowToast = showToast;
...@@ -171,6 +200,135 @@ public class FullscreenHtmlApiHandler { ...@@ -171,6 +200,135 @@ public class FullscreenHtmlApiHandler {
mPersistentModeSupplier = new ObservableSupplierImpl<>(); mPersistentModeSupplier = new ObservableSupplierImpl<>();
mPersistentModeSupplier.set(false); mPersistentModeSupplier.set(false);
mExitFullscreenOnStop = exitFullscreenOnStop;
}
/**
* Initialize the FullscreeHtmlApiHandler.
* @param activityTabProvider Provider of the current activity tab.
* @param modelSelector The tab model selector that will be monitored for tab changes.
*/
void initialize(ActivityTabProvider activityTabProvider, TabModelSelector modelSelector) {
ApplicationStatus.registerStateListenerForActivity(this, mActivity);
ApplicationStatus.registerWindowFocusChangedListener(this);
mActiveTabObserver = new ActivityTabTabObserver(activityTabProvider) {
@Override
protected void onObservingDifferentTab(Tab tab) {
mTab = tab;
setContentView(tab != null ? tab.getContentView() : null);
if (tab != null) updateMultiTouchZoomSupport(!getPersistentFullscreenMode());
}
};
mTabFullscreenObserver = new TabModelSelectorTabObserver(modelSelector) {
@Override
public void onContentChanged(Tab tab) {
setContentView(tab.getContentView());
}
@Override
public void onHidden(Tab tab, @TabHidingType int reason) {
// Clean up any fullscreen state that might impact other tabs.
exitPersistentFullscreenMode();
}
@Override
public void onDidFinishNavigation(Tab tab, NavigationHandle navigation) {
if (navigation.isInMainFrame() && !navigation.isSameDocument()) {
if (tab == mTab) exitPersistentFullscreenMode();
}
}
@Override
public void onInteractabilityChanged(Tab tab, boolean interactable) {
if (!interactable || tab != mTab) return;
Runnable enterFullscreen = getEnterFullscreenRunnable(tab);
if (enterFullscreen != null) enterFullscreen.run();
}
};
}
@Override
public void addObserver(FullscreenManager.Observer observer) {
mObservers.addObserver(observer);
}
@Override
public void removeObserver(FullscreenManager.Observer observer) {
mObservers.removeObserver(observer);
}
private void setContentView(ContentView contentView) {
if (contentView == mContentView) return;
if (mContentView != null) {
mContentView.removeOnSystemUiVisibilityChangeListener(this);
}
mContentView = contentView;
if (mContentView != null) {
mContentView.addOnSystemUiVisibilityChangeListener(this);
}
}
@Override
public void onEnterFullscreen(Tab tab, FullscreenOptions options) {
// If enabling fullscreen while the tab is not interactable, fullscreen
// will be delayed until the tab is interactable.
Runnable r = () -> {
enterPersistentFullscreenMode(options);
destroySelectActionMode(tab);
setEnterFullscreenRunnable(tab, null);
};
if (tab.isUserInteractable()) {
r.run();
} else {
setEnterFullscreenRunnable(tab, r);
}
for (FullscreenManager.Observer observer : mObservers) {
observer.onEnterFullscreen(tab, options);
}
}
@Override
public void onExitFullscreen(Tab tab) {
setEnterFullscreenRunnable(tab, null);
if (tab == mTab) exitPersistentFullscreenMode();
for (FullscreenManager.Observer observer : mObservers) {
observer.onExitFullscreen(tab);
}
}
/**
* @see GestureListenerManager#updateMultiTouchZoomSupport(boolean).
*/
private void updateMultiTouchZoomSupport(boolean enable) {
if (mTab == null || mTab.isHidden()) return;
WebContents webContents = mTab.getWebContents();
if (webContents != null) {
GestureListenerManager manager = GestureListenerManager.fromWebContents(webContents);
if (manager != null) manager.updateMultiTouchZoomSupport(enable);
}
}
private void destroySelectActionMode(Tab tab) {
WebContents webContents = tab.getWebContents();
if (webContents != null) {
SelectionPopupController.fromWebContents(webContents).destroySelectActionMode();
}
}
private void setEnterFullscreenRunnable(Tab tab, Runnable runnable) {
TabAttributes attrs = TabAttributes.from(tab);
if (runnable == null) {
attrs.clear(TabAttributeKeys.ENTER_FULLSCREEN);
} else {
attrs.set(TabAttributeKeys.ENTER_FULLSCREEN, runnable);
}
}
private Runnable getEnterFullscreenRunnable(Tab tab) {
return tab != null ? TabAttributes.from(tab).get(TabAttributeKeys.ENTER_FULLSCREEN) : null;
} }
/** /**
...@@ -179,19 +337,18 @@ public class FullscreenHtmlApiHandler { ...@@ -179,19 +337,18 @@ public class FullscreenHtmlApiHandler {
* *
* @param options Options to choose mode of fullscreen. * @param options Options to choose mode of fullscreen.
*/ */
public void enterPersistentFullscreenMode(FullscreenOptions options) { private void enterPersistentFullscreenMode(FullscreenOptions options) {
if (getPersistentFullscreenMode() && ObjectsCompat.equals(mFullscreenOptions, options)) { if (!getPersistentFullscreenMode() || ObjectsCompat.equals(mFullscreenOptions, options)) {
return; mPersistentModeSupplier.set(true);
} if (mAreControlsHidden.get()) {
// The browser controls are currently hidden.
mPersistentModeSupplier.set(true); enterFullscreen(mTab, options);
if (mAreControlsHidden.get()) { } else {
// The browser controls are currently hidden. // We should hide browser controls first.
enterFullscreen(mCurrentTab.get(), options); mPendingFullscreenOptions = options;
} else { }
// We should hide browser controls first.
mPendingFullscreenOptions = options;
} }
updateMultiTouchZoomSupport(false);
} }
/** /**
...@@ -200,38 +357,34 @@ public class FullscreenHtmlApiHandler { ...@@ -200,38 +357,34 @@ public class FullscreenHtmlApiHandler {
*/ */
private void maybeEnterFullscreenFromPendingState(boolean controlsHidden) { private void maybeEnterFullscreenFromPendingState(boolean controlsHidden) {
if (!controlsHidden) return; if (!controlsHidden) return;
Tab tab = mCurrentTab.get(); if (mTab != null && mPendingFullscreenOptions != null) {
if (tab != null && mPendingFullscreenOptions != null) { enterFullscreen(mTab, mPendingFullscreenOptions);
enterFullscreen(tab, mPendingFullscreenOptions);
mPendingFullscreenOptions = null; mPendingFullscreenOptions = null;
} }
} }
/** @Override
* Exits persistent fullscreen mode. Will restore browser controls visibility
* if they have been hidden.
*/
public void exitPersistentFullscreenMode() { public void exitPersistentFullscreenMode() {
if (!getPersistentFullscreenMode()) return; if (getPersistentFullscreenMode()) {
mPersistentModeSupplier.set(false);
mPersistentModeSupplier.set(false);
if (mWebContentsInFullscreen != null && mTabInFullscreen != null) {
if (mWebContentsInFullscreen != null && mTabInFullscreen != null) { exitFullscreen(
exitFullscreen(mWebContentsInFullscreen, mContentViewInFullscreen, mTabInFullscreen); mWebContentsInFullscreen, mContentViewInFullscreen, mTabInFullscreen);
} else { } else {
assert mPendingFullscreenOptions != null : "No content previously set to fullscreen."; assert mPendingFullscreenOptions
mPendingFullscreenOptions = null; != null : "No content previously set to fullscreen.";
mPendingFullscreenOptions = null;
}
mWebContentsInFullscreen = null;
mContentViewInFullscreen = null;
mTabInFullscreen = null;
mFullscreenOptions = null;
} }
mWebContentsInFullscreen = null; updateMultiTouchZoomSupport(true);
mContentViewInFullscreen = null;
mTabInFullscreen = null;
mFullscreenOptions = null;
} }
/** @Override
* @return Whether the application is in persistent fullscreen mode.
* @see #setPersistentFullscreenMode(boolean)
*/
public boolean getPersistentFullscreenMode() { public boolean getPersistentFullscreenMode() {
return mPersistentModeSupplier.get(); return mPersistentModeSupplier.get();
} }
...@@ -265,7 +418,7 @@ public class FullscreenHtmlApiHandler { ...@@ -265,7 +418,7 @@ public class FullscreenHtmlApiHandler {
// At this point, browser controls are hidden. Show browser controls only if // At this point, browser controls are hidden. Show browser controls only if
// it's permitted. // it's permitted.
TabBrowserControlsConstraintsHelper.update( TabBrowserControlsConstraintsHelper.update(
mCurrentTab.get(), BrowserControlsState.SHOWN, true); mTab, BrowserControlsState.SHOWN, true);
contentView.removeOnLayoutChangeListener(this); contentView.removeOnLayoutChangeListener(this);
} }
} }
...@@ -353,7 +506,7 @@ public class FullscreenHtmlApiHandler { ...@@ -353,7 +506,7 @@ public class FullscreenHtmlApiHandler {
mNotificationToast.cancel(); mNotificationToast.cancel();
} }
int resId = R.string.immersive_fullscreen_api_notification; int resId = R.string.immersive_fullscreen_api_notification;
mNotificationToast = Toast.makeText(mWindow.getContext(), resId, Toast.LENGTH_LONG); mNotificationToast = Toast.makeText(mActivity, resId, Toast.LENGTH_LONG);
mNotificationToast.setGravity(Gravity.TOP | Gravity.CENTER, 0, 0); mNotificationToast.setGravity(Gravity.TOP | Gravity.CENTER, 0, 0);
mNotificationToast.show(); mNotificationToast.show();
} }
...@@ -368,22 +521,35 @@ public class FullscreenHtmlApiHandler { ...@@ -368,22 +521,35 @@ public class FullscreenHtmlApiHandler {
} }
} }
/** // ActivityStateListener
* Notified when the system UI visibility for the current ContentView has changed.
* @param visibility The updated UI visibility. @Override
* @see View#getSystemUiVisibility() public void onActivityStateChange(Activity activity, int newState) {
*/ if (newState == ActivityState.STOPPED && mExitFullscreenOnStop) {
public void onContentViewSystemUiVisibilityChange(int visibility) { // Exit fullscreen in onStop to ensure the system UI flags are set correctly when
// showing again (on JB MR2+ builds, the omnibox would be covered by the
// notification bar when this was done in onStart()).
exitPersistentFullscreenMode();
} else if (newState == ActivityState.DESTROYED) {
ApplicationStatus.unregisterActivityStateListener(this);
ApplicationStatus.unregisterWindowFocusChangedListener(this);
}
}
// View.OnSystemUiVisibilityChangeListener
@Override
public void onSystemUiVisibilityChange(int visibility) {
if (mTabInFullscreen == null || !getPersistentFullscreenMode()) return; if (mTabInFullscreen == null || !getPersistentFullscreenMode()) return;
mHandler.sendEmptyMessageDelayed( mHandler.sendEmptyMessageDelayed(
MSG_ID_SET_FULLSCREEN_SYSTEM_UI_FLAGS, ANDROID_CONTROLS_SHOW_DURATION_MS); MSG_ID_SET_FULLSCREEN_SYSTEM_UI_FLAGS, ANDROID_CONTROLS_SHOW_DURATION_MS);
} }
/** // WindowFocusChangedListener
* Ensure the proper system UI flags are set after the window regains focus.
* @see android.app.Activity#onWindowFocusChanged(boolean) @Override
*/ public void onWindowFocusChanged(Activity activity, boolean hasWindowFocus) {
public void onWindowFocusChanged(boolean hasWindowFocus) { if (mActivity != activity) return;
if (!hasWindowFocus) hideNotificationToast(); if (!hasWindowFocus) hideNotificationToast();
mHandler.removeMessages(MSG_ID_SET_FULLSCREEN_SYSTEM_UI_FLAGS); mHandler.removeMessages(MSG_ID_SET_FULLSCREEN_SYSTEM_UI_FLAGS);
...@@ -425,25 +591,37 @@ public class FullscreenHtmlApiHandler { ...@@ -425,25 +591,37 @@ public class FullscreenHtmlApiHandler {
/* /*
* Clears the current window attributes to not contain windowFlags. This * Clears the current window attributes to not contain windowFlags. This
* is slightly different that mWindow.clearFlags which then sets a * is slightly different that Window.clearFlags which then sets a
* forced window attribute on the Window object that cannot be cleared. * forced window attribute on the Window object that cannot be cleared.
*/ */
private void clearWindowFlags(int windowFlags) { private void clearWindowFlags(int windowFlags) {
final WindowManager.LayoutParams attrs = mWindow.getAttributes(); Window window = mActivity.getWindow();
final WindowManager.LayoutParams attrs = window.getAttributes();
if ((attrs.flags & windowFlags) != 0) { if ((attrs.flags & windowFlags) != 0) {
attrs.flags &= ~windowFlags; attrs.flags &= ~windowFlags;
mWindow.setAttributes(attrs); window.setAttributes(attrs);
} }
} }
/* /*
* Sets the current window attributes to contain windowFlags. This * Sets the current window attributes to contain windowFlags. This
* is slightly different that mWindow.setFlags which then sets a * is slightly different that Window.setFlags which then sets a
* forced window attribute on the Window object that cannot be cleared. * forced window attribute on the Window object that cannot be cleared.
*/ */
private void setWindowFlags(int windowFlags) { private void setWindowFlags(int windowFlags) {
final WindowManager.LayoutParams attrs = mWindow.getAttributes(); Window window = mActivity.getWindow();
final WindowManager.LayoutParams attrs = window.getAttributes();
attrs.flags |= windowFlags; attrs.flags |= windowFlags;
mWindow.setAttributes(attrs); window.setAttributes(attrs);
}
/**
* Destroys the FullscreenHtmlApiHandler.
*/
public void destroy() {
mTab = null;
setContentView(null);
if (mActiveTabObserver != null) mActiveTabObserver.destroy();
if (mTabFullscreenObserver != null) mTabFullscreenObserver.destroy();
} }
} }
...@@ -49,6 +49,13 @@ public interface FullscreenManager { ...@@ -49,6 +49,13 @@ public interface FullscreenManager {
*/ */
void exitPersistentFullscreenMode(); void exitPersistentFullscreenMode();
/**
* Enter fullscreen.
* @param tab {@link Tab} that goes into fullscreen.
* @param options Fullscreen options.
*/
void onEnterFullscreen(Tab tab, FullscreenOptions options);
/** /**
* Exit fullscreen. * Exit fullscreen.
* @param tab {@link Tab} that goes out of fullscreen. * @param tab {@link Tab} that goes out of fullscreen.
......
...@@ -70,6 +70,7 @@ public class FullscreenManagerUnitTest { ...@@ -70,6 +70,7 @@ public class FullscreenManagerUnitTest {
private UserDataHost mUserDataHost = new UserDataHost(); private UserDataHost mUserDataHost = new UserDataHost();
private ChromeFullscreenManager mFullscreenManager; private ChromeFullscreenManager mFullscreenManager;
private boolean mControlsResizeView;
@Before @Before
public void setUp() { public void setUp() {
...@@ -96,6 +97,9 @@ public class FullscreenManagerUnitTest { ...@@ -96,6 +97,9 @@ public class FullscreenManagerUnitTest {
mFullscreenManager.initialize(mControlContainer, mActivityTabProvider, mTabModelSelector, mFullscreenManager.initialize(mControlContainer, mActivityTabProvider, mTabModelSelector,
R.dimen.control_container_height); R.dimen.control_container_height);
mFullscreenManager.addObserver(mBrowserControlsStateProviderObserver); mFullscreenManager.addObserver(mBrowserControlsStateProviderObserver);
mFullscreenManager.setViewportSizeDelegate(() -> {
mControlsResizeView = BrowserControlsUtils.controlsResizeView(mFullscreenManager);
});
when(mFullscreenManager.getTab()).thenReturn(mTab); when(mFullscreenManager.getTab()).thenReturn(mTab);
} }
...@@ -128,13 +132,13 @@ public class FullscreenManagerUnitTest { ...@@ -128,13 +132,13 @@ public class FullscreenManagerUnitTest {
final int topHeight = 100; final int topHeight = 100;
final int topMinHeight = 0; final int topMinHeight = 0;
TabModelSelectorTabObserver tabFullscreenObserver = TabModelSelectorTabObserver tabControlsObserver =
mFullscreenManager.getTabFullscreenObserverForTesting(); mFullscreenManager.getTabControlsObserverForTesting();
mFullscreenManager.setTopControlsHeight(topHeight, topMinHeight); mFullscreenManager.setTopControlsHeight(topHeight, topMinHeight);
// Send initial offsets. // Send initial offsets.
tabFullscreenObserver.onBrowserControlsOffsetChanged(mTab, /*topControlsOffsetY*/ 0, tabControlsObserver.onBrowserControlsOffsetChanged(mTab, /*topControlsOffsetY*/ 0,
/*bottomControlsOffsetY*/ 0, /*contentOffsetY*/ 100, /*bottomControlsOffsetY*/ 0, /*contentOffsetY*/ 100,
/*topControlsMinHeightOffsetY*/ 0, /*bottomControlsMinHeightOffsetY*/ 0); /*topControlsMinHeightOffsetY*/ 0, /*bottomControlsMinHeightOffsetY*/ 0);
// Initially, the controls should be fully visible. // Initially, the controls should be fully visible.
...@@ -142,20 +146,20 @@ public class FullscreenManagerUnitTest { ...@@ -142,20 +146,20 @@ public class FullscreenManagerUnitTest {
BrowserControlsUtils.areBrowserControlsFullyVisible(mFullscreenManager)); BrowserControlsUtils.areBrowserControlsFullyVisible(mFullscreenManager));
assertTrue("ControlsResizeView is false," assertTrue("ControlsResizeView is false,"
+ " but it should be true when the controls are fully visible.", + " but it should be true when the controls are fully visible.",
mFullscreenManager.controlsResizeView()); mControlsResizeView);
// Scroll to fully hidden. // Scroll to fully hidden.
tabFullscreenObserver.onBrowserControlsOffsetChanged(mTab, /*topControlsOffsetY*/ -100, tabControlsObserver.onBrowserControlsOffsetChanged(mTab, /*topControlsOffsetY*/ -100,
/*bottomControlsOffsetY*/ 0, /*contentOffsetY*/ 0, /*bottomControlsOffsetY*/ 0, /*contentOffsetY*/ 0,
/*topControlsMinHeightOffsetY*/ 0, /*bottomControlsMinHeightOffsetY*/ 0); /*topControlsMinHeightOffsetY*/ 0, /*bottomControlsMinHeightOffsetY*/ 0);
assertTrue("Browser controls aren't at min-height.", assertTrue("Browser controls aren't at min-height.",
mFullscreenManager.areBrowserControlsAtMinHeight()); mFullscreenManager.areBrowserControlsAtMinHeight());
assertFalse("ControlsResizeView is true," assertFalse("ControlsResizeView is true,"
+ " but it should be false when the controls are hidden.", + " but it should be false when the controls are hidden.",
mFullscreenManager.controlsResizeView()); mControlsResizeView);
// Now, scroll back to fully visible. // Now, scroll back to fully visible.
tabFullscreenObserver.onBrowserControlsOffsetChanged(mTab, /*topControlsOffsetY*/ 0, tabControlsObserver.onBrowserControlsOffsetChanged(mTab, /*topControlsOffsetY*/ 0,
/*bottomControlsOffsetY*/ 0, /*contentOffsetY*/ 100, /*bottomControlsOffsetY*/ 0, /*contentOffsetY*/ 100,
/*topControlsMinHeightOffsetY*/ 0, /*bottomControlsMinHeightOffsetY*/ 0); /*topControlsMinHeightOffsetY*/ 0, /*bottomControlsMinHeightOffsetY*/ 0);
assertFalse("Browser controls are hidden when they should be fully visible.", assertFalse("Browser controls are hidden when they should be fully visible.",
...@@ -165,7 +169,7 @@ public class FullscreenManagerUnitTest { ...@@ -165,7 +169,7 @@ public class FullscreenManagerUnitTest {
// #controlsResizeView should be flipped back to true. // #controlsResizeView should be flipped back to true.
assertTrue("ControlsResizeView is false," assertTrue("ControlsResizeView is false,"
+ " but it should be true when the controls are fully visible.", + " but it should be true when the controls are fully visible.",
mFullscreenManager.controlsResizeView()); mControlsResizeView);
} }
@Test @Test
...@@ -179,14 +183,14 @@ public class FullscreenManagerUnitTest { ...@@ -179,14 +183,14 @@ public class FullscreenManagerUnitTest {
final int bottomHeight = 60; final int bottomHeight = 60;
final int bottomMinHeight = 0; final int bottomMinHeight = 0;
TabModelSelectorTabObserver tabFullscreenObserver = TabModelSelectorTabObserver tabControlsObserver =
mFullscreenManager.getTabFullscreenObserverForTesting(); mFullscreenManager.getTabControlsObserverForTesting();
mFullscreenManager.setTopControlsHeight(topHeight, topMinHeight); mFullscreenManager.setTopControlsHeight(topHeight, topMinHeight);
mFullscreenManager.setBottomControlsHeight(bottomHeight, bottomMinHeight); mFullscreenManager.setBottomControlsHeight(bottomHeight, bottomMinHeight);
// Send initial offsets. // Send initial offsets.
tabFullscreenObserver.onBrowserControlsOffsetChanged(mTab, /*topControlsOffsetY*/ 0, tabControlsObserver.onBrowserControlsOffsetChanged(mTab, /*topControlsOffsetY*/ 0,
/*bottomControlsOffsetY*/ 0, /*contentOffsetY*/ 100, /*bottomControlsOffsetY*/ 0, /*contentOffsetY*/ 100,
/*topControlsMinHeightOffsetY*/ 25, /*bottomControlsMinHeightOffsetY*/ 0); /*topControlsMinHeightOffsetY*/ 25, /*bottomControlsMinHeightOffsetY*/ 0);
// Initially, the controls should be fully visible. // Initially, the controls should be fully visible.
...@@ -194,20 +198,20 @@ public class FullscreenManagerUnitTest { ...@@ -194,20 +198,20 @@ public class FullscreenManagerUnitTest {
BrowserControlsUtils.areBrowserControlsFullyVisible(mFullscreenManager)); BrowserControlsUtils.areBrowserControlsFullyVisible(mFullscreenManager));
assertTrue("ControlsResizeView is false," assertTrue("ControlsResizeView is false,"
+ " but it should be true when the controls are fully visible.", + " but it should be true when the controls are fully visible.",
mFullscreenManager.controlsResizeView()); mControlsResizeView);
// Scroll all the way to the min-height. // Scroll all the way to the min-height.
tabFullscreenObserver.onBrowserControlsOffsetChanged(mTab, /*topControlsOffsetY*/ -75, tabControlsObserver.onBrowserControlsOffsetChanged(mTab, /*topControlsOffsetY*/ -75,
/*bottomControlsOffsetY*/ 60, /*contentOffsetY*/ 25, /*bottomControlsOffsetY*/ 60, /*contentOffsetY*/ 25,
/*topControlsMinHeightOffsetY*/ 25, /*bottomControlsMinHeightOffsetY*/ 0); /*topControlsMinHeightOffsetY*/ 25, /*bottomControlsMinHeightOffsetY*/ 0);
assertTrue("Browser controls aren't at min-height.", assertTrue("Browser controls aren't at min-height.",
mFullscreenManager.areBrowserControlsAtMinHeight()); mFullscreenManager.areBrowserControlsAtMinHeight());
assertFalse("ControlsResizeView is true," assertFalse("ControlsResizeView is true,"
+ " but it should be false when the controls are at min-height.", + " but it should be false when the controls are at min-height.",
mFullscreenManager.controlsResizeView()); mControlsResizeView);
// Now, scroll back to fully visible. // Now, scroll back to fully visible.
tabFullscreenObserver.onBrowserControlsOffsetChanged(mTab, /*topControlsOffsetY*/ 0, tabControlsObserver.onBrowserControlsOffsetChanged(mTab, /*topControlsOffsetY*/ 0,
/*bottomControlsOffsetY*/ 0, /*contentOffsetY*/ 100, /*bottomControlsOffsetY*/ 0, /*contentOffsetY*/ 100,
/*topControlsMinHeightOffsetY*/ 25, /*bottomControlsMinHeightOffsetY*/ 0); /*topControlsMinHeightOffsetY*/ 25, /*bottomControlsMinHeightOffsetY*/ 0);
assertFalse("Browser controls are at min-height when they should be fully visible.", assertFalse("Browser controls are at min-height when they should be fully visible.",
...@@ -217,7 +221,7 @@ public class FullscreenManagerUnitTest { ...@@ -217,7 +221,7 @@ public class FullscreenManagerUnitTest {
// #controlsResizeView should be flipped back to true. // #controlsResizeView should be flipped back to true.
assertTrue("ControlsResizeView is false," assertTrue("ControlsResizeView is false,"
+ " but it should be true when the controls are fully visible.", + " but it should be true when the controls are fully visible.",
mFullscreenManager.controlsResizeView()); mControlsResizeView);
} }
@Test @Test
...@@ -231,41 +235,41 @@ public class FullscreenManagerUnitTest { ...@@ -231,41 +235,41 @@ public class FullscreenManagerUnitTest {
final int bottomHeight = 60; final int bottomHeight = 60;
final int bottomMinHeight = 0; final int bottomMinHeight = 0;
TabModelSelectorTabObserver tabFullscreenObserver = TabModelSelectorTabObserver tabControlsObserver =
mFullscreenManager.getTabFullscreenObserverForTesting(); mFullscreenManager.getTabControlsObserverForTesting();
mFullscreenManager.setTopControlsHeight(topHeight, topMinHeight); mFullscreenManager.setTopControlsHeight(topHeight, topMinHeight);
mFullscreenManager.setBottomControlsHeight(bottomHeight, bottomMinHeight); mFullscreenManager.setBottomControlsHeight(bottomHeight, bottomMinHeight);
// Send initial offsets. // Send initial offsets.
tabFullscreenObserver.onBrowserControlsOffsetChanged(mTab, /*topControlsOffsetY*/ 0, tabControlsObserver.onBrowserControlsOffsetChanged(mTab, /*topControlsOffsetY*/ 0,
/*bottomControlsOffsetY*/ 0, /*contentOffsetY*/ 100, /*bottomControlsOffsetY*/ 0, /*contentOffsetY*/ 100,
/*topControlsMinHeightOffsetY*/ 25, /*bottomControlsMinHeightOffsetY*/ 0); /*topControlsMinHeightOffsetY*/ 25, /*bottomControlsMinHeightOffsetY*/ 0);
assertTrue("ControlsResizeView is false," assertTrue("ControlsResizeView is false,"
+ " but it should be true when the controls are fully visible.", + " but it should be true when the controls are fully visible.",
mFullscreenManager.controlsResizeView()); mControlsResizeView);
// Scroll a little hide the controls partially. // Scroll a little hide the controls partially.
tabFullscreenObserver.onBrowserControlsOffsetChanged(mTab, /*topControlsOffsetY*/ -25, tabControlsObserver.onBrowserControlsOffsetChanged(mTab, /*topControlsOffsetY*/ -25,
/*bottomControlsOffsetY*/ 20, /*contentOffsetY*/ 75, /*bottomControlsOffsetY*/ 20, /*contentOffsetY*/ 75,
/*topControlsMinHeightOffsetY*/ 25, /*bottomControlsMinHeightOffsetY*/ 0); /*topControlsMinHeightOffsetY*/ 25, /*bottomControlsMinHeightOffsetY*/ 0);
assertTrue("ControlsResizeView is false, but it should still be true.", assertTrue(
mFullscreenManager.controlsResizeView()); "ControlsResizeView is false, but it should still be true.", mControlsResizeView);
// Scroll controls all the way to the min-height. // Scroll controls all the way to the min-height.
tabFullscreenObserver.onBrowserControlsOffsetChanged(mTab, /*topControlsOffsetY*/ -75, tabControlsObserver.onBrowserControlsOffsetChanged(mTab, /*topControlsOffsetY*/ -75,
/*bottomControlsOffsetY*/ 60, /*contentOffsetY*/ 25, /*bottomControlsOffsetY*/ 60, /*contentOffsetY*/ 25,
/*topControlsMinHeightOffsetY*/ 25, /*bottomControlsMinHeightOffsetY*/ 0); /*topControlsMinHeightOffsetY*/ 25, /*bottomControlsMinHeightOffsetY*/ 0);
assertFalse("ControlsResizeView is true," assertFalse("ControlsResizeView is true,"
+ " but it should've flipped to false since the controls are idle now.", + " but it should've flipped to false since the controls are idle now.",
mFullscreenManager.controlsResizeView()); mControlsResizeView);
// Scroll controls to show a little more. // Scroll controls to show a little more.
tabFullscreenObserver.onBrowserControlsOffsetChanged(mTab, /*topControlsOffsetY*/ -50, tabControlsObserver.onBrowserControlsOffsetChanged(mTab, /*topControlsOffsetY*/ -50,
/*bottomControlsOffsetY*/ 40, /*contentOffsetY*/ 50, /*bottomControlsOffsetY*/ 40, /*contentOffsetY*/ 50,
/*topControlsMinHeightOffsetY*/ 25, /*bottomControlsMinHeightOffsetY*/ 0); /*topControlsMinHeightOffsetY*/ 25, /*bottomControlsMinHeightOffsetY*/ 0);
assertFalse("ControlsResizeView is true, but it should still be false.", assertFalse(
mFullscreenManager.controlsResizeView()); "ControlsResizeView is true, but it should still be false.", mControlsResizeView);
} }
// --- controlsResizeView tests // --- controlsResizeView tests
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment