Commit fae6aebd authored by Becky Zhou's avatar Becky Zhou Committed by Commit Bot

[TabModal] Add toolbar animation on JS dialog shown

Add animation for the Android toolbar view to slide in when JavaScript
tab modal dialog is showing and the renderer is blocked on input events.

Bug: 817461
Change-Id: I3ed69ffabe736100ac209be59f34eeedd4189cee
Reviewed-on: https://chromium-review.googlesource.com/942378
Commit-Queue: Becky Zhou <huayinz@chromium.org>
Reviewed-by: default avatarTed Choc <tedchoc@chromium.org>
Reviewed-by: default avatarMatthew Jones <mdjones@chromium.org>
Cr-Commit-Position: refs/heads/master@{#547062}
parent 98ce3845
......@@ -544,6 +544,9 @@ public class ChromeFullscreenManager
private boolean shouldShowAndroidControls() {
if (mBrowserControlsAndroidViewHidden) return false;
if (getTab() != null && getTab().getControlsOffsetHelper().isControlsOffsetOverridden()) {
return true;
}
boolean showControls = !drawControlsAsTexture();
ContentViewCore contentViewCore = getActiveContentViewCore();
......
......@@ -206,8 +206,8 @@ public class ModalDialogManager {
* @param dialog The dialog to be cancelled.
*/
public void cancelDialog(ModalDialogView dialog) {
dismissDialog(dialog);
dialog.getController().onCancel();
dismissDialog(dialog);
}
/**
......
......@@ -4,6 +4,8 @@
package org.chromium.chrome.browser.modaldialog;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.content.res.Resources;
import android.view.Gravity;
import android.view.View;
......@@ -18,6 +20,7 @@ import org.chromium.chrome.browser.ChromeActivity;
import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel;
import org.chromium.chrome.browser.contextualsearch.ContextualSearchManager;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tab.TabBrowserControlsOffsetHelper;
import org.chromium.chrome.browser.widget.bottomsheet.BottomSheet;
import org.chromium.chrome.browser.widget.bottomsheet.BottomSheetObserver;
import org.chromium.chrome.browser.widget.bottomsheet.EmptyBottomSheetObserver;
......@@ -25,11 +28,16 @@ import org.chromium.content_public.browser.ContentViewCore;
import org.chromium.content_public.browser.SelectionPopupController;
import org.chromium.content_public.browser.WebContents;
import org.chromium.ui.UiUtils;
import org.chromium.ui.interpolators.BakedBezierInterpolator;
/**
* The presenter that displays a single tab modal dialog.
*/
public class TabModalPresenter extends ModalDialogManager.Presenter {
public class TabModalPresenter
extends ModalDialogManager.Presenter implements TabBrowserControlsOffsetHelper.Observer {
// TODO(huayinz): Confirm duration with UX.
private static final int ENTER_EXIT_ANIMATION_DURATION_MS = 200;
/** The activity displaying the dialogs. */
private final ChromeActivity mChromeActivity;
......@@ -54,6 +62,12 @@ public class TabModalPresenter extends ModalDialogManager.Presenter {
/** Whether the dialog container is brought to the front in its parent. */
private boolean mContainerIsAtFront;
/**
* Whether an enter animation on the dialog container should run when
* {@link #onBrowserControlsFullyVisible} is called.
*/
private boolean mRunEnterAnimationOnCallback;
/** Whether the action bar on selected text is temporarily cleared for showing dialogs. */
private boolean mDidClearTextControls;
......@@ -64,6 +78,9 @@ public class TabModalPresenter extends ModalDialogManager.Presenter {
*/
private View mDefaultNextSiblingView;
/** Enter and exit animation duration that can be overwritten in tests. */
private int mEnterExitAnimationDurationMs;
/**
* Constructor for initializing dialog container.
* @param chromeActivity The activity displaying the dialogs.
......@@ -71,6 +88,7 @@ public class TabModalPresenter extends ModalDialogManager.Presenter {
public TabModalPresenter(ChromeActivity chromeActivity) {
mChromeActivity = chromeActivity;
mHasBottomControls = mChromeActivity.getBottomSheet() != null;
mEnterExitAnimationDurationMs = ENTER_EXIT_ANIMATION_DURATION_MS;
if (mHasBottomControls) {
mBottomSheetObserver = new EmptyBottomSheetObserver() {
......@@ -91,11 +109,12 @@ public class TabModalPresenter extends ModalDialogManager.Presenter {
protected void addDialogView(View dialogView) {
if (mDialogContainer == null) initDialogContainer();
setBrowserControlsAccess(true);
mDialogContainer.setVisibility(View.VISIBLE);
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
MarginLayoutParams.WRAP_CONTENT, MarginLayoutParams.WRAP_CONTENT, Gravity.CENTER);
mDialogContainer.addView(dialogView, params);
// Don't show the dialog container before browser controls are guaranteed fully visible.
if (mActiveTab.getControlsOffsetHelper().areBrowserControlsFullyVisible()) {
runEnterAnimation(dialogView);
} else {
mRunEnterAnimationOnCallback = true;
}
mChromeActivity.addViewObscuringAllTabs(mDialogContainer);
updateContainerHierarchy(true);
}
......@@ -103,13 +122,27 @@ public class TabModalPresenter extends ModalDialogManager.Presenter {
@Override
protected void removeDialogView(View dialogView) {
setBrowserControlsAccess(false);
// Don't run exit animation if enter animation has not yet started.
if (mRunEnterAnimationOnCallback) {
mRunEnterAnimationOnCallback = false;
} else {
// Clear focus so that keyboard can hide accordingly while entering tab switcher.
dialogView.clearFocus();
mDialogContainer.removeView(dialogView);
mDialogContainer.setVisibility(View.GONE);
runExitAnimation(dialogView);
}
mChromeActivity.removeViewObscuringAllTabs(mDialogContainer);
}
@Override
public void onBrowserControlsFullyVisible(Tab tab) {
if (getModalDialog() == null) return;
assert mActiveTab == tab;
if (mRunEnterAnimationOnCallback) {
mRunEnterAnimationOnCallback = false;
runEnterAnimation(getModalDialog().getView());
}
}
/**
* Change view hierarchy for the dialog container to be either the front most or beneath the
* toolbar.
......@@ -146,6 +179,7 @@ public class TabModalPresenter extends ModalDialogManager.Presenter {
dialogContainerStub.setLayoutResource(R.layout.modal_dialog_container);
mDialogContainer = (ViewGroup) dialogContainerStub.inflate();
mDialogContainer.setVisibility(View.GONE);
mContainerParent = (ViewGroup) mDialogContainer.getParent();
// The default sibling view is the next view of the dialog container stub in main.xml and
// should not be removed from its parent.
......@@ -192,6 +226,7 @@ public class TabModalPresenter extends ModalDialogManager.Presenter {
assert mActiveTab
!= null : "Tab modal dialogs should be shown on top of an active tab.";
mActiveTab.getControlsOffsetHelper().addObserver(this);
// Hide contextual search panel so that bottom toolbar will not be
// obscured and back press is not overridden.
ContextualSearchManager contextualSearchManager =
......@@ -213,8 +248,6 @@ public class TabModalPresenter extends ModalDialogManager.Presenter {
}
// Force toolbar to show and disable overflow menu.
// TODO(huayinz): figure out a way to avoid |UpdateBrowserControlsState| being blocked
// by render process stalled due to javascript dialog.
mActiveTab.onTabModalDialogStateChanged(true);
if (mHasBottomControls) {
......@@ -225,6 +258,7 @@ public class TabModalPresenter extends ModalDialogManager.Presenter {
}
menuButton.setEnabled(false);
} else {
mActiveTab.getControlsOffsetHelper().removeObserver(this);
// Show the action bar back if it was dismissed when the dialogs were showing.
if (mDidClearTextControls) {
mDidClearTextControls = false;
......@@ -242,6 +276,45 @@ public class TabModalPresenter extends ModalDialogManager.Presenter {
}
}
/**
* Helper method to run fade-in animation when the specified dialog view is shown.
* @param dialogView The dialog view to be shown.
*/
private void runEnterAnimation(View dialogView) {
mDialogContainer.animate().cancel();
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
MarginLayoutParams.WRAP_CONTENT, MarginLayoutParams.WRAP_CONTENT, Gravity.CENTER);
mDialogContainer.addView(dialogView, params);
mDialogContainer.setAlpha(0f);
mDialogContainer.setVisibility(View.VISIBLE);
mDialogContainer.animate()
.setDuration(mEnterExitAnimationDurationMs)
.alpha(1f)
.setInterpolator(BakedBezierInterpolator.FADE_IN_CURVE)
.setListener(null)
.start();
}
/**
* Helper method to run fade-out animation when the specified dialog view is dismissed.
* @param dialogView The dismissed dialog view.
*/
private void runExitAnimation(View dialogView) {
mDialogContainer.animate().cancel();
mDialogContainer.animate()
.setDuration(mEnterExitAnimationDurationMs)
.alpha(0f)
.setInterpolator(BakedBezierInterpolator.FADE_OUT_CURVE)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mDialogContainer.setVisibility(View.GONE);
mDialogContainer.removeView(dialogView);
}
})
.start();
}
@VisibleForTesting
View getDialogContainerForTest() {
return mDialogContainer;
......@@ -251,4 +324,9 @@ public class TabModalPresenter extends ModalDialogManager.Presenter {
ViewGroup getContainerParentForTest() {
return mContainerParent;
}
@VisibleForTesting
void disableAnimationForTest() {
mEnterExitAnimationDurationMs = 0;
}
}
......@@ -87,7 +87,6 @@ import org.chromium.chrome.browser.tabmodel.AsyncTabParamsManager;
import org.chromium.chrome.browser.tabmodel.TabModel;
import org.chromium.chrome.browser.tabmodel.TabModel.TabLaunchType;
import org.chromium.chrome.browser.tabmodel.TabModel.TabSelectionType;
import org.chromium.chrome.browser.tabmodel.TabModelImpl;
import org.chromium.chrome.browser.tabmodel.TabModelSelector;
import org.chromium.chrome.browser.tabmodel.TabReparentingParams;
import org.chromium.chrome.browser.util.ColorUtils;
......@@ -364,9 +363,7 @@ public class Tab
private TabRedirectHandler mTabRedirectHandler;
private FullscreenManager mFullscreenManager;
private float mPreviousTopControlsOffsetY = Float.NaN;
private float mPreviousBottomControlsOffsetY = Float.NaN;
private float mPreviousContentOffsetY = Float.NaN;
private final TabBrowserControlsOffsetHelper mControlsOffsetHelper;
/**
* Indicates whether this tab is detached from any activity and its corresponding
......@@ -617,6 +614,8 @@ public class Tab
ContextualSearchTabHelper.createForTab(this);
MediaSessionTabHelper.createForTab(this);
mControlsOffsetHelper = new TabBrowserControlsOffsetHelper(this);
if (creationState != null) {
mTabUma = new TabUma(creationState);
if (frozenState == null) {
......@@ -2017,10 +2016,7 @@ public class Tab
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
notifyContentChanged();
}
FullscreenManager fullscreenManager = getFullscreenManager();
if (fullscreenManager != null) {
fullscreenManager.setPositionsForTabToNonFullscreen();
}
mControlsOffsetHelper.showAndroidControls(false);
}
/**
......@@ -2106,9 +2102,7 @@ public class Tab
mInfoBarContainer = null;
}
mPreviousTopControlsOffsetY = Float.NaN;
mPreviousBottomControlsOffsetY = Float.NaN;
mPreviousContentOffsetY = Float.NaN;
mControlsOffsetHelper.clearPreviousPositions();
mNeedsReload = false;
}
......@@ -2805,33 +2799,6 @@ public class Tab
}
}
/**
* Called when offset values related with fullscreen functionality has been changed by the
* compositor.
* @param topControlsOffsetY The Y offset of the top controls in physical pixels.
* {@code Float.NaN} if the value is invalid and the cached value should be used.
* @param bottomControlsOffsetY The Y offset of the bottom controls in physical pixels.
* {@code Float.NaN} if the value is invalid and the cached value should be used.
* @param contentOffsetY The Y offset of the content in physical pixels.
*/
void onOffsetsChanged(
float topControlsOffsetY, float bottomControlsOffsetY, float contentOffsetY) {
if (!Float.isNaN(topControlsOffsetY)) mPreviousTopControlsOffsetY = topControlsOffsetY;
if (!Float.isNaN(bottomControlsOffsetY)) {
mPreviousBottomControlsOffsetY = bottomControlsOffsetY;
}
if (!Float.isNaN(contentOffsetY)) mPreviousContentOffsetY = contentOffsetY;
if (mFullscreenManager == null) return;
if (isShowingSadTab() || isNativePage()) {
mFullscreenManager.setPositionsForTabToNonFullscreen();
} else {
mFullscreenManager.setPositionsForTab(mPreviousTopControlsOffsetY,
mPreviousBottomControlsOffsetY, mPreviousContentOffsetY);
}
TabModelImpl.setActualTabSwitchLatencyMetricRequired();
}
/**
* Push state about whether or not the browser controls can show or hide to the renderer.
*/
......@@ -2963,24 +2930,7 @@ public class Tab
*/
public void setFullscreenManager(FullscreenManager manager) {
mFullscreenManager = manager;
if (mFullscreenManager != null) {
boolean topOffsetsInitialized = !Float.isNaN(mPreviousTopControlsOffsetY)
&& !Float.isNaN(mPreviousContentOffsetY);
boolean bottomOffsetsInitialized =
!Float.isNaN(mPreviousBottomControlsOffsetY);
boolean isChromeHomeEnabled = FeatureUtilities.isChromeHomeEnabled();
// Make sure the dominant control offsets have been set.
if ((!topOffsetsInitialized && !isChromeHomeEnabled)
|| (!bottomOffsetsInitialized && isChromeHomeEnabled)) {
mFullscreenManager.setPositionsForTabToNonFullscreen();
} else {
mFullscreenManager.setPositionsForTab(mPreviousTopControlsOffsetY,
mPreviousBottomControlsOffsetY,
mPreviousContentOffsetY);
}
updateFullscreenEnabledState();
}
mControlsOffsetHelper.resetPositions();
}
/**
......@@ -3338,7 +3288,7 @@ public class Tab
mIsRendererUnresponsive = true;
if (mFullscreenManager == null) return;
mFullscreenManager.setPositionsForTabToNonFullscreen();
mControlsOffsetHelper.showAndroidControls(false);
updateBrowserControlsState(BrowserControlsState.SHOWN, false);
}
......@@ -3438,9 +3388,27 @@ public class Tab
*/
public void onTabModalDialogStateChanged(boolean isShowing) {
mIsShowingTabModalDialog = isShowing;
if (mFullscreenManager == null) return;
mFullscreenManager.setPositionsForTabToNonFullscreen();
updateBrowserControlsState(BrowserControlsState.SHOWN, false);
// Also need to update browser control state after dismissal to refresh the constraints.
if (isShowing && areRendererInputEventsIgnored()) {
mControlsOffsetHelper.showAndroidControls(true);
} else {
updateBrowserControlsState(BrowserControlsState.SHOWN,
!mControlsOffsetHelper.isControlsOffsetOverridden());
}
}
/**
* @return Whether input events from the renderer are ignored on the browser side.
*/
boolean areRendererInputEventsIgnored() {
return nativeAreRendererInputEventsIgnored(mNativeTabAndroid);
}
/**
* @return The {@link TabBrowserControlsOffsetHelper} for this tab.
*/
public TabBrowserControlsOffsetHelper getControlsOffsetHelper() {
return mControlsOffsetHelper;
}
@CalledByNative
......@@ -3573,4 +3541,5 @@ public class Tab
private native void nativeAttachDetachedTab(long nativeTabAndroid);
private native void nativeMediaDownloadInProductHelpDismissed(long nativeTabAndroid);
private native int nativeGetCurrentRenderProcessId(long nativeTabAndroid);
private native boolean nativeAreRendererInputEventsIgnored(long nativeTabAndroid);
}
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.tab;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import org.chromium.base.ObserverList;
import org.chromium.chrome.browser.fullscreen.FullscreenManager;
import org.chromium.chrome.browser.tabmodel.TabModelImpl;
import org.chromium.chrome.browser.util.FeatureUtilities;
/**
* Handles browser controls offset for a Tab.
*/
public class TabBrowserControlsOffsetHelper {
/**
* Maximum duration for the control container slide-in animation. Note that this value matches
* the one in browser_controls_offset_manager.cc.
*/
private static final int MAX_CONTROLS_ANIMATION_DURATION_MS = 200;
/**
* An interface for notification about browser controls offset updates.
*/
public interface Observer {
/**
* Called when the browser controls are fully visible on screen.
*/
void onBrowserControlsFullyVisible(Tab tab);
}
private final Tab mTab;
private final ObserverList<Observer> mObservers = new ObserverList<>();
private float mPreviousTopControlsOffsetY = Float.NaN;
private float mPreviousBottomControlsOffsetY = Float.NaN;
private float mPreviousContentOffsetY = Float.NaN;
/**
* Whether the Android browser controls offset is overridden. This handles top controls only.
*/
private boolean mIsControlsOffsetOverridden;
/**
* The animator for slide-in animation on the Android controls.
*/
private ValueAnimator mControlsAnimator;
/**
* @param tab The {@link Tab} that this class is associated with.
*/
TabBrowserControlsOffsetHelper(Tab tab) {
mTab = tab;
}
/**
* @return Whether the Android browser controls offset is overridden on the browser side.
*/
public boolean isControlsOffsetOverridden() {
return mIsControlsOffsetOverridden;
}
/**
* @return Whether the browser controls are fully visible on screen.
*/
public boolean areBrowserControlsFullyVisible() {
final FullscreenManager manager = mTab.getFullscreenManager();
return Float.compare(0f, manager.getBrowserControlHiddenRatio()) == 0;
}
/**
* @param observer The observer to be added to get notifications from this class.
*/
public void addObserver(Observer observer) {
mObservers.addObserver(observer);
}
/**
* @param observer The observer to be removed to cancel notifications from this class.
*/
public void removeObserver(Observer observer) {
mObservers.removeObserver(observer);
}
/**
* Called when offset values related with fullscreen functionality has been changed by the
* compositor.
* @param topControlsOffsetY The Y offset of the top controls in physical pixels.
* {@code Float.NaN} if the value is invalid and the cached value should be used.
* @param bottomControlsOffsetY The Y offset of the bottom controls in physical pixels.
* {@code Float.NaN} if the value is invalid and the cached value should be used.
* @param contentOffsetY The Y offset of the content in physical pixels.
*/
void onOffsetsChanged(
float topControlsOffsetY, float bottomControlsOffsetY, float contentOffsetY) {
// Cancel any animation on the Android controls and let compositor drive the offset updates.
resetControlsOffsetOverridden();
if (!Float.isNaN(topControlsOffsetY)) mPreviousTopControlsOffsetY = topControlsOffsetY;
if (!Float.isNaN(bottomControlsOffsetY)) {
mPreviousBottomControlsOffsetY = bottomControlsOffsetY;
}
if (!Float.isNaN(contentOffsetY)) mPreviousContentOffsetY = contentOffsetY;
if (mTab.getFullscreenManager() == null) return;
if (mTab.isShowingSadTab() || mTab.isNativePage()) {
showAndroidControls(false);
} else {
updateFullscreenManagerOffsets(false, mPreviousTopControlsOffsetY,
mPreviousBottomControlsOffsetY, mPreviousContentOffsetY);
}
TabModelImpl.setActualTabSwitchLatencyMetricRequired();
}
/**
* Shows the Android browser controls view.
* @param animate Whether a slide-in animation should be run.
*/
void showAndroidControls(boolean animate) {
if (mTab.getFullscreenManager() == null) return;
if (animate) {
runBrowserDrivenShowAnimation();
} else {
updateFullscreenManagerOffsets(true, Float.NaN, Float.NaN, Float.NaN);
}
}
/**
* Resets the controls positions in {@link FullscreenManager} to the cached positions.
*/
void resetPositions() {
resetControlsOffsetOverridden();
if (mTab.getFullscreenManager() == null) return;
boolean topOffsetsInitialized =
!Float.isNaN(mPreviousTopControlsOffsetY) && !Float.isNaN(mPreviousContentOffsetY);
boolean bottomOffsetsInitialized = !Float.isNaN(mPreviousBottomControlsOffsetY);
boolean isChromeHomeEnabled = FeatureUtilities.isChromeHomeEnabled();
// Make sure the dominant control offsets have been set.
if ((!topOffsetsInitialized && !isChromeHomeEnabled)
|| (!bottomOffsetsInitialized && isChromeHomeEnabled)) {
showAndroidControls(false);
} else {
updateFullscreenManagerOffsets(false, mPreviousTopControlsOffsetY,
mPreviousBottomControlsOffsetY, mPreviousContentOffsetY);
}
mTab.updateFullscreenEnabledState();
}
/**
* Clears the cached browser controls positions.
*/
void clearPreviousPositions() {
mPreviousTopControlsOffsetY = Float.NaN;
mPreviousBottomControlsOffsetY = Float.NaN;
mPreviousContentOffsetY = Float.NaN;
}
/**
* Helper method to update offsets in {@link FullscreenManager} and notify offset changes to
* observers if necessary.
*/
private void updateFullscreenManagerOffsets(boolean toNonFullscreen, float topControlsOffset,
float bottomControlsOffset, float topContentOffset) {
final FullscreenManager manager = mTab.getFullscreenManager();
if (toNonFullscreen) {
manager.setPositionsForTabToNonFullscreen();
} else {
manager.setPositionsForTab(topControlsOffset, bottomControlsOffset, topContentOffset);
}
if (!areBrowserControlsFullyVisible()) return;
for (Observer observer : mObservers) {
observer.onBrowserControlsFullyVisible(mTab);
}
}
/**
* Helper method to cancel overridden offset on Android browser controls.
*/
private void resetControlsOffsetOverridden() {
if (!mIsControlsOffsetOverridden) return;
if (mControlsAnimator != null) mControlsAnimator.cancel();
mIsControlsOffsetOverridden = false;
}
/**
* Helper method to run slide-in animations on the Android browser controls views.
*/
private void runBrowserDrivenShowAnimation() {
if (mControlsAnimator != null) return;
mIsControlsOffsetOverridden = true;
final FullscreenManager manager = mTab.getFullscreenManager();
final float hiddenRatio = manager.getBrowserControlHiddenRatio();
final float topControlHeight = manager.getTopControlsHeight();
final float topControlOffset = hiddenRatio == 0f ? 0f : hiddenRatio * -topControlHeight;
// Set animation start value to current renderer controls offset.
mControlsAnimator = ValueAnimator.ofFloat(topControlOffset, 0f);
mControlsAnimator.setDuration(
(long) Math.abs(hiddenRatio * MAX_CONTROLS_ANIMATION_DURATION_MS));
mControlsAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mControlsAnimator = null;
mPreviousTopControlsOffsetY = 0f;
mPreviousContentOffsetY = topControlHeight;
}
@Override
public void onAnimationCancel(Animator animation) {
updateFullscreenManagerOffsets(false, topControlHeight, 0, topControlHeight);
}
});
mControlsAnimator.addUpdateListener((animator) -> {
updateFullscreenManagerOffsets(
false, (float) animator.getAnimatedValue(), 0, topControlHeight);
});
mControlsAnimator.start();
}
}
......@@ -30,12 +30,14 @@ class TabViewAndroidDelegate extends ViewAndroidDelegate {
@Override
public void onTopControlsChanged(float topControlsOffsetY, float topContentOffsetY) {
mTab.onOffsetsChanged(topControlsOffsetY, Float.NaN, topContentOffsetY);
mTab.getControlsOffsetHelper().onOffsetsChanged(
topControlsOffsetY, Float.NaN, topContentOffsetY);
}
@Override
public void onBottomControlsChanged(float bottomControlsOffsetY, float bottomContentOffsetY) {
mTab.onOffsetsChanged(Float.NaN, bottomControlsOffsetY, Float.NaN);
mTab.getControlsOffsetHelper().onOffsetsChanged(
Float.NaN, bottomControlsOffsetY, Float.NaN);
}
@Override
......
......@@ -242,6 +242,9 @@ public class ToolbarControlContainer extends FrameLayout implements ControlConta
// Don't eat the event if we don't have a handler.
if (mSwipeHandler == null) return false;
// Don't react on touch events if the toolbar container is not fully visible.
if (!isFullyVisible()) return true;
// If we have ACTION_DOWN in this context, that means either no child consumed the event or
// this class is the top UI at the event position. Then, we don't need to feed the event to
// mGestureDetector here because the event is already once fed in onInterceptTouchEvent().
......@@ -256,6 +259,7 @@ public class ToolbarControlContainer extends FrameLayout implements ControlConta
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
if (!isFullyVisible()) return true;
if (mSwipeHandler == null || isOnTabStrip(event)) return false;
return mSwipeRecognizer.onTouchEvent(event);
......@@ -265,6 +269,13 @@ public class ToolbarControlContainer extends FrameLayout implements ControlConta
return e.getY() <= mTabStripHeight;
}
/**
* @return Whether or not the control container is fully visible on screen.
*/
private boolean isFullyVisible() {
return Float.compare(0f, getTranslationY()) == 0;
}
private class SwipeRecognizerImpl extends SwipeRecognizer {
public SwipeRecognizerImpl(Context context) {
super(context);
......
......@@ -1214,6 +1214,7 @@ chrome_java_sources = [
"java/src/org/chromium/chrome/browser/tab/SadTabView.java",
"java/src/org/chromium/chrome/browser/tab/SadTabViewFactory.java",
"java/src/org/chromium/chrome/browser/tab/Tab.java",
"java/src/org/chromium/chrome/browser/tab/TabBrowserControlsOffsetHelper.java",
"java/src/org/chromium/chrome/browser/tab/TabContextMenuItemDelegate.java",
"java/src/org/chromium/chrome/browser/tab/TabContextMenuPopulator.java",
"java/src/org/chromium/chrome/browser/tab/TabDelegateFactory.java",
......
......@@ -77,6 +77,9 @@ public class ModalDialogManagerTest {
mTestObserver = new TestObserver();
mActivity.getToolbarManager().getToolbarLayout().getLocationBar().addUrlFocusChangeListener(
mTestObserver);
TabModalPresenter presenter =
(TabModalPresenter) mManager.getPresenterForTest(ModalDialogManager.TAB_MODAL);
presenter.disableAnimationForTest();
}
@Test
......
......@@ -976,6 +976,14 @@ void TabAndroid::DidFinishNavigation(
j_publisher_url);
}
bool TabAndroid::AreRendererInputEventsIgnored(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj) {
content::RenderProcessHost* render_process_host =
web_contents()->GetMainFrame()->GetProcess();
return render_process_host->IgnoreInputEvents();
}
void TabAndroid::ShowMediaDownloadInProductHelp(
const gfx::Rect& rect_in_frame) {
DCHECK(web_contents_);
......
......@@ -303,6 +303,10 @@ class TabAndroid : public CoreTabHelperDelegate,
void DidFinishNavigation(
content::NavigationHandle* navigation_handle) override;
bool AreRendererInputEventsIgnored(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj);
private:
class MediaDownloadInProductHelp;
......
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