Commit ece08cd7 authored by Mehran Mahmoudi's avatar Mehran Mahmoudi Committed by Commit Bot

[Paint Preview] Disable toolbar hide on scroll when Paint Preview showing

This CL introduces the new PaintPreviewWindowAndroidHelper class. This
class stores activity-specific variables in PaintPreviewHelper. Using
the BrowserControlsManager class, it makes the top toolbar persistent
when a Paint Preview is shown.

This CL also fixes a bug where TabbedPaintPreviewPlayer#onDismiss was
never called.

Bug: 1131497
Change-Id: I3caf7017f601536ba03c1e1c60c9b024917f6063
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2425433
Commit-Queue: Mehran Mahmoudi <mahmoudi@chromium.org>
Reviewed-by: default avatarCalder Kitagawa <ckitagawa@chromium.org>
Cr-Commit-Position: refs/heads/master@{#810838}
parent c2b4d7c7
...@@ -4,11 +4,15 @@ ...@@ -4,11 +4,15 @@
package org.chromium.chrome.browser.paint_preview; package org.chromium.chrome.browser.paint_preview;
import android.app.Activity;
import android.os.SystemClock; import android.os.SystemClock;
import org.chromium.base.ActivityState;
import org.chromium.base.ApplicationStatus;
import org.chromium.chrome.browser.app.ChromeActivity; import org.chromium.chrome.browser.app.ChromeActivity;
import org.chromium.chrome.browser.flags.CachedFeatureFlags; import org.chromium.chrome.browser.flags.CachedFeatureFlags;
import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.fullscreen.BrowserControlsManager;
import org.chromium.chrome.browser.metrics.PageLoadMetrics; import org.chromium.chrome.browser.metrics.PageLoadMetrics;
import org.chromium.chrome.browser.metrics.UmaUtils; import org.chromium.chrome.browser.metrics.UmaUtils;
import org.chromium.chrome.browser.multiwindow.MultiWindowUtils; import org.chromium.chrome.browser.multiwindow.MultiWindowUtils;
...@@ -18,6 +22,10 @@ import org.chromium.chrome.browser.tabmodel.EmptyTabModelSelectorObserver; ...@@ -18,6 +22,10 @@ import org.chromium.chrome.browser.tabmodel.EmptyTabModelSelectorObserver;
import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.browser.tabmodel.TabModelSelector;
import org.chromium.chrome.browser.util.ChromeAccessibilityUtil; import org.chromium.chrome.browser.util.ChromeAccessibilityUtil;
import org.chromium.content_public.browser.WebContents; import org.chromium.content_public.browser.WebContents;
import org.chromium.ui.base.WindowAndroid;
import java.util.HashMap;
import java.util.Map;
/** /**
* Handles initialization of the Paint Preview tab observers. * Handles initialization of the Paint Preview tab observers.
...@@ -31,9 +39,12 @@ public class PaintPreviewHelper { ...@@ -31,9 +39,12 @@ public class PaintPreviewHelper {
private static boolean sHasAttemptedToShowOnRestore; private static boolean sHasAttemptedToShowOnRestore;
/** /**
* Tracks the activity creation time in ms from {@link SystemClock#elapsedRealtime}. * A map for keeping Activity-specific variables and classes. New entries are added on calls
* to {@link #initialize(ChromeActivity, TabModelSelector)}. Entries are automatically removed
* when their respective Activity is destroyed.
*/ */
private static long sActivityCreationTimeMs; private static Map<WindowAndroid, PaintPreviewWindowAndroidHelper> sWindowAndroidHelperMap =
new HashMap<>();
/** /**
* Initializes the logic required for the Paint Preview on startup feature. Mainly, observes a * Initializes the logic required for the Paint Preview on startup feature. Mainly, observes a
...@@ -41,13 +52,14 @@ public class PaintPreviewHelper { ...@@ -41,13 +52,14 @@ public class PaintPreviewHelper {
* @param activity The ChromeActivity that corresponds to the tabModelSelector. * @param activity The ChromeActivity that corresponds to the tabModelSelector.
* @param tabModelSelector The TabModelSelector to observe. * @param tabModelSelector The TabModelSelector to observe.
*/ */
public static void initialize(ChromeActivity activity, TabModelSelector tabModelSelector) { public static void initialize(ChromeActivity<?> activity, TabModelSelector tabModelSelector) {
if (!CachedFeatureFlags.isEnabled(ChromeFeatureList.PAINT_PREVIEW_SHOW_ON_STARTUP)) return; if (!CachedFeatureFlags.isEnabled(ChromeFeatureList.PAINT_PREVIEW_SHOW_ON_STARTUP)) return;
if (!MultiWindowUtils.getInstance().areMultipleChromeInstancesRunning(activity)) { if (!MultiWindowUtils.getInstance().areMultipleChromeInstancesRunning(activity)) {
sHasAttemptedToShowOnRestore = false; sHasAttemptedToShowOnRestore = false;
} }
sActivityCreationTimeMs = activity.getOnCreateTimestampMs(); sWindowAndroidHelperMap.put(
activity.getWindowAndroid(), new PaintPreviewWindowAndroidHelper(activity));
// TODO(crbug/1074428): verify this doesn't cause a memory leak if the user exits Chrome // TODO(crbug/1074428): verify this doesn't cause a memory leak if the user exits Chrome
// prior to onTabStateInitialized being called. // prior to onTabStateInitialized being called.
...@@ -66,22 +78,23 @@ public class PaintPreviewHelper { ...@@ -66,22 +78,23 @@ public class PaintPreviewHelper {
} }
/** /**
* Attempts to display the Paint Preview representation of for the given Tab. * Attempts to display the Paint Preview representation for the given Tab.
* @param onShown The callback for when the Paint Preview is shown.
* @param onDismissed The callback for when the Paint Preview is dismissed.
* @return Whether the Paint Preview started to initialize or is already initializating.
* Note that if the Paint Preview is already showing, this will return false.
*/ */
public static boolean showPaintPreviewOnRestore(Tab tab) { public static void showPaintPreviewOnRestore(Tab tab) {
if (!CachedFeatureFlags.isEnabled(ChromeFeatureList.PAINT_PREVIEW_SHOW_ON_STARTUP) if (!CachedFeatureFlags.isEnabled(ChromeFeatureList.PAINT_PREVIEW_SHOW_ON_STARTUP)
|| sHasAttemptedToShowOnRestore || sHasAttemptedToShowOnRestore
|| ChromeAccessibilityUtil.get().isAccessibilityEnabled()) { || ChromeAccessibilityUtil.get().isAccessibilityEnabled()) {
return false; return;
} }
sHasAttemptedToShowOnRestore = true; PaintPreviewWindowAndroidHelper windowAndroidHelper =
sWindowAndroidHelperMap.get(tab.getWindowAndroid());
if (windowAndroidHelper == null) return;
sHasAttemptedToShowOnRestore = true;
TabbedPaintPreviewPlayer player = TabbedPaintPreviewPlayer.get(tab); TabbedPaintPreviewPlayer player = TabbedPaintPreviewPlayer.get(tab);
player.setBrowserVisibilityDelegate(
windowAndroidHelper.getBrowserControlsManager().getBrowserVisibilityDelegate());
PageLoadMetrics.Observer observer = new PageLoadMetrics.Observer() { PageLoadMetrics.Observer observer = new PageLoadMetrics.Observer() {
@Override @Override
public void onFirstMeaningfulPaint(WebContents webContents, long navigationId, public void onFirstMeaningfulPaint(WebContents webContents, long navigationId,
...@@ -90,16 +103,49 @@ public class PaintPreviewHelper { ...@@ -90,16 +103,49 @@ public class PaintPreviewHelper {
} }
}; };
if (!player.maybeShow(() -> { if (!player.maybeShow(()
PageLoadMetrics.removeObserver(observer); -> PageLoadMetrics.removeObserver(observer),
}, sActivityCreationTimeMs, () -> { windowAndroidHelper.getActivityCreationTime(),
return UmaUtils.hasComeToForeground() && !UmaUtils.hasComeToBackground(); () -> UmaUtils.hasComeToForeground() && !UmaUtils.hasComeToBackground())) {
})) { return;
return false;
} }
PageLoadMetrics.addObserver(observer); PageLoadMetrics.addObserver(observer);
}
return true; /**
* A helper class for keeping activity-specific variables and classes.
*/
private static class PaintPreviewWindowAndroidHelper
implements ApplicationStatus.ActivityStateListener {
/**
* Tracks the activity creation time in ms from {@link SystemClock#elapsedRealtime}.
*/
private long mActivityCreationTime;
private WindowAndroid mWindowAndroid;
private BrowserControlsManager mBrowserControlsManager;
PaintPreviewWindowAndroidHelper(ChromeActivity<?> chromeActivity) {
mWindowAndroid = chromeActivity.getWindowAndroid();
mActivityCreationTime = chromeActivity.getOnCreateTimestampMs();
mBrowserControlsManager = chromeActivity.getBrowserControlsManager();
ApplicationStatus.registerStateListenerForActivity(this, chromeActivity);
}
long getActivityCreationTime() {
return mActivityCreationTime;
}
BrowserControlsManager getBrowserControlsManager() {
return mBrowserControlsManager;
}
@Override
public void onActivityStateChange(Activity activity, @ActivityState int newState) {
if (newState == ActivityState.DESTROYED) {
sWindowAndroidHelperMap.remove(mWindowAndroid);
ApplicationStatus.unregisterActivityStateListener(this);
}
}
} }
} }
...@@ -34,6 +34,7 @@ android_library("java") { ...@@ -34,6 +34,7 @@ android_library("java") {
"//base:base_java", "//base:base_java",
"//base:jni_java", "//base:jni_java",
"//chrome/browser/android/lifecycle:java", "//chrome/browser/android/lifecycle:java",
"//chrome/browser/browser_controls/android:java",
"//chrome/browser/flags:java", "//chrome/browser/flags:java",
"//chrome/browser/tab:java", "//chrome/browser/tab:java",
"//chrome/browser/tabmodel:java", "//chrome/browser/tabmodel:java",
......
...@@ -15,6 +15,7 @@ import android.view.View; ...@@ -15,6 +15,7 @@ import android.view.View;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import org.chromium.base.UserData; import org.chromium.base.UserData;
import org.chromium.chrome.browser.browser_controls.BrowserStateBrowserControlsVisibilityDelegate;
import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.paint_preview.TabbedPaintPreviewMetricsHelper.ExitCause; import org.chromium.chrome.browser.paint_preview.TabbedPaintPreviewMetricsHelper.ExitCause;
import org.chromium.chrome.browser.paint_preview.services.PaintPreviewTabService; import org.chromium.chrome.browser.paint_preview.services.PaintPreviewTabService;
...@@ -31,6 +32,7 @@ import org.chromium.components.paintpreview.player.PlayerManager; ...@@ -31,6 +32,7 @@ import org.chromium.components.paintpreview.player.PlayerManager;
import org.chromium.content_public.browser.LoadUrlParams; import org.chromium.content_public.browser.LoadUrlParams;
import org.chromium.content_public.browser.NavigationHandle; import org.chromium.content_public.browser.NavigationHandle;
import org.chromium.content_public.browser.WebContents; import org.chromium.content_public.browser.WebContents;
import org.chromium.ui.util.TokenHolder;
import org.chromium.url.GURL; import org.chromium.url.GURL;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
...@@ -61,6 +63,8 @@ public class TabbedPaintPreviewPlayer implements TabViewProvider, UserData { ...@@ -61,6 +63,8 @@ public class TabbedPaintPreviewPlayer implements TabViewProvider, UserData {
private boolean mFadingOut; private boolean mFadingOut;
private int mSnackbarShownCount; private int mSnackbarShownCount;
private TabbedPaintPreviewMetricsHelper mMetricsHelper; private TabbedPaintPreviewMetricsHelper mMetricsHelper;
private BrowserStateBrowserControlsVisibilityDelegate mBrowserVisibilityDelegate;
private int mPersistentToolbarToken = TokenHolder.INVALID_TOKEN;
public static TabbedPaintPreviewPlayer get(Tab tab) { public static TabbedPaintPreviewPlayer get(Tab tab) {
if (tab.getUserDataHost().getUserData(USER_DATA_KEY) == null) { if (tab.getUserDataHost().getUserData(USER_DATA_KEY) == null) {
...@@ -116,6 +120,8 @@ public class TabbedPaintPreviewPlayer implements TabViewProvider, UserData { ...@@ -116,6 +120,8 @@ public class TabbedPaintPreviewPlayer implements TabViewProvider, UserData {
@Override @Override
public void onHidden(Tab tab, @TabHidingType int hidingType) { public void onHidden(Tab tab, @TabHidingType int hidingType) {
releasePersistentToolbar();
if (mPlayerManager == null || !isShowingAndNeedsBadge()) return; if (mPlayerManager == null || !isShowingAndNeedsBadge()) return;
// If the tab is hidden as a result of pausing the activity we shouldn't remove it. // If the tab is hidden as a result of pausing the activity we shouldn't remove it.
...@@ -123,6 +129,11 @@ public class TabbedPaintPreviewPlayer implements TabViewProvider, UserData { ...@@ -123,6 +129,11 @@ public class TabbedPaintPreviewPlayer implements TabViewProvider, UserData {
removePaintPreview(ExitCause.TAB_HIDDEN); removePaintPreview(ExitCause.TAB_HIDDEN);
} }
@Override
public void onShown(Tab tab, int type) {
if (isShowingAndNeedsBadge()) showToolbarPersistent();
}
} }
private TabbedPaintPreviewPlayer(Tab tab) { private TabbedPaintPreviewPlayer(Tab tab) {
...@@ -133,6 +144,11 @@ public class TabbedPaintPreviewPlayer implements TabViewProvider, UserData { ...@@ -133,6 +144,11 @@ public class TabbedPaintPreviewPlayer implements TabViewProvider, UserData {
mTab.addObserver(mObserver); mTab.addObserver(mObserver);
} }
public void setBrowserVisibilityDelegate(
BrowserStateBrowserControlsVisibilityDelegate browserVisibilityDelegate) {
mBrowserVisibilityDelegate = browserVisibilityDelegate;
}
/** /**
* Triggered via {@link PageLoadMetrics.Observer} when First Meaningful Paint happens. * Triggered via {@link PageLoadMetrics.Observer} when First Meaningful Paint happens.
* @param webContents the webContents that triggered the event. * @param webContents the webContents that triggered the event.
...@@ -207,11 +223,12 @@ public class TabbedPaintPreviewPlayer implements TabViewProvider, UserData { ...@@ -207,11 +223,12 @@ public class TabbedPaintPreviewPlayer implements TabViewProvider, UserData {
*/ */
private void removePaintPreview(@ExitCause int exitCause) { private void removePaintPreview(@ExitCause int exitCause) {
PaintPreviewCompositorUtils.stopWarmCompositor(); PaintPreviewCompositorUtils.stopWarmCompositor();
mOnDismissed = null;
mInitializing = false; mInitializing = false;
if (mTab == null || mPlayerManager == null || mFadingOut) return; if (mTab == null || mPlayerManager == null || mFadingOut) return;
mFadingOut = true; mFadingOut = true;
if (mOnDismissed != null) mOnDismissed.run();
mOnDismissed = null;
Point scrollPosition = mPlayerManager.getScrollPosition(); Point scrollPosition = mPlayerManager.getScrollPosition();
if (mTab.getWebContents() != null && scrollPosition != null) { if (mTab.getWebContents() != null && scrollPosition != null) {
mTab.getWebContents().getEventForwarder().scrollTo(scrollPosition.x, scrollPosition.y); mTab.getWebContents().getEventForwarder().scrollTo(scrollPosition.x, scrollPosition.y);
...@@ -276,6 +293,25 @@ public class TabbedPaintPreviewPlayer implements TabViewProvider, UserData { ...@@ -276,6 +293,25 @@ public class TabbedPaintPreviewPlayer implements TabViewProvider, UserData {
mTab.loadUrl(new LoadUrlParams(url.getSpec())); mTab.loadUrl(new LoadUrlParams(url.getSpec()));
} }
/**
* Persistently shows the toolbar and avoids hiding it on scrolling down.
*/
private void showToolbarPersistent() {
if (mBrowserVisibilityDelegate == null
|| mPersistentToolbarToken != TokenHolder.INVALID_TOKEN) {
return;
}
mPersistentToolbarToken = mBrowserVisibilityDelegate.showControlsPersistent();
}
private void releasePersistentToolbar() {
if (mBrowserVisibilityDelegate == null) return;
mBrowserVisibilityDelegate.releasePersistentShowingToken(mPersistentToolbarToken);
mPersistentToolbarToken = TokenHolder.INVALID_TOKEN;
}
@Override @Override
public int getTabViewProviderType() { public int getTabViewProviderType() {
return Type.PAINT_PREVIEW; return Type.PAINT_PREVIEW;
...@@ -286,9 +322,14 @@ public class TabbedPaintPreviewPlayer implements TabViewProvider, UserData { ...@@ -286,9 +322,14 @@ public class TabbedPaintPreviewPlayer implements TabViewProvider, UserData {
return mPlayerManager == null ? null : mPlayerManager.getView(); return mPlayerManager == null ? null : mPlayerManager.getView();
} }
@Override
public void onShown() {
showToolbarPersistent();
}
@Override @Override
public void onHidden() { public void onHidden() {
if (mOnDismissed != null) mOnDismissed.run(); releasePersistentToolbar();
} }
@Override @Override
......
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