summaryrefslogtreecommitdiff
path: root/chromium/weblayer/browser/java/org/chromium/weblayer_private/InfoBarContainerView.java
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/weblayer/browser/java/org/chromium/weblayer_private/InfoBarContainerView.java')
-rw-r--r--chromium/weblayer/browser/java/org/chromium/weblayer_private/InfoBarContainerView.java257
1 files changed, 257 insertions, 0 deletions
diff --git a/chromium/weblayer/browser/java/org/chromium/weblayer_private/InfoBarContainerView.java b/chromium/weblayer/browser/java/org/chromium/weblayer_private/InfoBarContainerView.java
new file mode 100644
index 00000000000..553608310f2
--- /dev/null
+++ b/chromium/weblayer/browser/java/org/chromium/weblayer_private/InfoBarContainerView.java
@@ -0,0 +1,257 @@
+// Copyright 2013 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.weblayer_private;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.content.Context;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+import android.widget.RelativeLayout;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.VisibleForTesting;
+
+import org.chromium.base.MathUtils;
+import org.chromium.ui.display.DisplayAndroid;
+import org.chromium.ui.display.DisplayUtil;
+
+/**
+ * The {@link View} for the {@link InfoBarContainer}.
+ */
+public class InfoBarContainerView extends SwipableOverlayView {
+ /**
+ * Observes container view changes.
+ */
+ public interface ContainerViewObserver extends InfoBarContainer.InfoBarAnimationListener {
+ /**
+ * Called when the height of shown content changed.
+ * @param shownFraction The ratio of height of shown content to the height of the container
+ * view.
+ */
+ void onShownRatioChanged(float shownFraction);
+ }
+
+ /** Top margin, including the toolbar and tabstrip height and 48dp of web contents. */
+ private static final int TOP_MARGIN_PHONE_DP = 104;
+ private static final int TOP_MARGIN_TABLET_DP = 144;
+
+ /** Length of the animation to fade the InfoBarContainer back into View. */
+ private static final long REATTACH_FADE_IN_MS = 250;
+
+ /** Whether or not the InfoBarContainer is allowed to hide when the user scrolls. */
+ private static boolean sIsAllowedToAutoHide = true;
+
+ private final ContainerViewObserver mContainerViewObserver;
+ private final InfoBarContainerLayout mLayout;
+
+ /** Parent view that contains the InfoBarContainerLayout. */
+ private ViewGroup mParentView;
+
+ private TabImpl mTab;
+
+ /** Animation used to snap the container to the nearest state if scroll direction changes. */
+ private Animator mScrollDirectionChangeAnimation;
+
+ /** Whether or not the current scroll is downward. */
+ private boolean mIsScrollingDownward;
+
+ /** Tracks the previous event's scroll offset to determine if a scroll is up or down. */
+ private int mLastScrollOffsetY;
+
+ /**
+ * @param context The {@link Context} that this view is attached to.
+ * @param containerViewObserver The {@link ContainerViewObserver} that gets notified on
+ * container view changes.
+ * @param isTablet Whether this view is displayed on tablet or not.
+ */
+ InfoBarContainerView(@NonNull Context context,
+ @NonNull ContainerViewObserver containerViewObserver, TabImpl tab, boolean isTablet) {
+ super(context, null);
+ mTab = tab;
+ mContainerViewObserver = containerViewObserver;
+
+ // TODO(newt): move this workaround into the infobar views if/when they're scrollable.
+ // Workaround for http://crbug.com/407149. See explanation in onMeasure() below.
+ setVerticalScrollBarEnabled(false);
+
+ updateLayoutParams(context, isTablet);
+
+ Runnable makeContainerVisibleRunnable = () -> runUpEventAnimation(true);
+ mLayout = new InfoBarContainerLayout(context, makeContainerVisibleRunnable,
+ new InfoBarContainer.InfoBarAnimationListener() {
+ @Override
+ public void notifyAnimationFinished(int animationType) {
+ mContainerViewObserver.notifyAnimationFinished(animationType);
+ }
+
+ @Override
+ public void notifyAllAnimationsFinished(InfoBarUiItem frontInfoBar) {
+ mContainerViewObserver.notifyAllAnimationsFinished(frontInfoBar);
+ }
+ });
+
+ addView(mLayout,
+ new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT,
+ Gravity.CENTER_HORIZONTAL));
+ }
+
+ void destroy() {
+ removeFromParentView();
+ mTab = null;
+ }
+
+ // SwipableOverlayView implementation.
+ @Override
+ @VisibleForTesting
+ public boolean isAllowedToAutoHide() {
+ return sIsAllowedToAutoHide;
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ if (getVisibility() != View.GONE) {
+ setVisibility(VISIBLE);
+ setAlpha(0f);
+ animate().alpha(1f).setDuration(REATTACH_FADE_IN_MS);
+ }
+ }
+
+ @Override
+ protected void runUpEventAnimation(boolean visible) {
+ if (mScrollDirectionChangeAnimation != null) mScrollDirectionChangeAnimation.cancel();
+ super.runUpEventAnimation(visible);
+ }
+
+ @Override
+ protected boolean isIndependentlyAnimating() {
+ return mScrollDirectionChangeAnimation != null;
+ }
+
+ // View implementation.
+ @Override
+ public void setTranslationY(float translationY) {
+ int contentHeightDelta = mTab != null
+ ? mTab.getBrowser().getViewController().getBottomContentHeightDelta()
+ : 0;
+
+ // Push the infobar container up by any delta caused by the bottom toolbar while ensuring
+ // that it does not ascend beyond the top of the bottom toolbar nor descend beyond its own
+ // height.
+ float newTranslationY = MathUtils.clamp(
+ translationY - contentHeightDelta, -contentHeightDelta, getHeight());
+
+ super.setTranslationY(newTranslationY);
+
+ float shownFraction = 0;
+ if (getHeight() > 0) {
+ shownFraction = contentHeightDelta > 0 ? 1f : 1f - (translationY / getHeight());
+ }
+ mContainerViewObserver.onShownRatioChanged(shownFraction);
+ }
+
+ /**
+ * Sets whether the InfoBarContainer is allowed to auto-hide when the user scrolls the page.
+ * Expected to be called when Touch Exploration is enabled.
+ * @param isAllowed Whether auto-hiding is allowed.
+ */
+ public static void setIsAllowedToAutoHide(boolean isAllowed) {
+ sIsAllowedToAutoHide = isAllowed;
+ }
+
+ /**
+ * Notifies that an infobar's View ({@link InfoBar#getView}) has changed. If the infobar is
+ * visible, a view swapping animation will be run.
+ */
+ void notifyInfoBarViewChanged() {
+ mLayout.notifyInfoBarViewChanged();
+ }
+
+ /**
+ * Sets the parent {@link ViewGroup} that contains the {@link InfoBarContainer}.
+ */
+ void setParentView(ViewGroup parent) {
+ mParentView = parent;
+ // Don't attach the container to the new parent if it is not previously attached.
+ if (removeFromParentView()) addToParentView();
+ }
+
+ /**
+ * Adds this class to the parent view {@link #mParentView}.
+ */
+ void addToParentView() {
+ // If mTab is null, destroy() was called. This should not be added after destroyed.
+ assert mTab != null;
+ super.addToParentView(mParentView,
+ mTab.getBrowser().getViewController().getDesiredInfoBarContainerViewIndex());
+ }
+
+ /**
+ * Adds an {@link InfoBar} to the layout.
+ * @param infoBar The {@link InfoBar} to be added.
+ */
+ void addInfoBar(InfoBar infoBar) {
+ infoBar.createView();
+ mLayout.addInfoBar(infoBar);
+ }
+
+ /**
+ * Removes an {@link InfoBar} from the layout.
+ * @param infoBar The {@link InfoBar} to be removed.
+ */
+ void removeInfoBar(InfoBar infoBar) {
+ mLayout.removeInfoBar(infoBar);
+ }
+
+ /**
+ * Hides or stops hiding this View.
+ * @param isHidden Whether this View is should be hidden.
+ */
+ void setHidden(boolean isHidden) {
+ setVisibility(isHidden ? View.GONE : View.VISIBLE);
+ }
+
+ /**
+ * Run an animation when the scrolling direction of a gesture has changed (this does not mean
+ * the gesture has ended).
+ * @param visible Whether or not the view should be visible.
+ */
+ private void runDirectionChangeAnimation(boolean visible) {
+ mScrollDirectionChangeAnimation = createVerticalSnapAnimation(visible);
+ mScrollDirectionChangeAnimation.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mScrollDirectionChangeAnimation = null;
+ }
+ });
+ mScrollDirectionChangeAnimation.start();
+ }
+
+ @Override
+ // Ensure that this view's custom layout params are passed when adding it to its parent.
+ public ViewGroup.MarginLayoutParams createLayoutParams() {
+ return (ViewGroup.MarginLayoutParams) getLayoutParams();
+ }
+
+ private void updateLayoutParams(Context context, boolean isTablet) {
+ RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(
+ LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
+ lp.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
+ int topMarginDp = isTablet ? TOP_MARGIN_TABLET_DP : TOP_MARGIN_PHONE_DP;
+ lp.topMargin = DisplayUtil.dpToPx(DisplayAndroid.getNonMultiDisplay(context), topMarginDp);
+ setLayoutParams(lp);
+ }
+
+ /**
+ * Returns true if any animations are pending or in progress.
+ */
+ @VisibleForTesting
+ public boolean isAnimating() {
+ return mLayout.isAnimating();
+ }
+}