| Index: chrome/android/java/src/org/chromium/chrome/browser/infobar/ContentWrapperView.java
|
| diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/ContentWrapperView.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/ContentWrapperView.java
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..79e6d902056112dce37fb4d783c0ba9f87cadc6f
|
| --- /dev/null
|
| +++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/ContentWrapperView.java
|
| @@ -0,0 +1,254 @@
|
| +// Copyright (c) 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.chrome.browser.infobar;
|
| +
|
| +import android.animation.Animator;
|
| +import android.animation.ObjectAnimator;
|
| +import android.content.Context;
|
| +import android.content.res.Resources;
|
| +import android.graphics.Rect;
|
| +import android.view.Gravity;
|
| +import android.view.MotionEvent;
|
| +import android.view.View;
|
| +import android.view.ViewGroup;
|
| +import android.view.ViewParent;
|
| +import android.widget.FrameLayout;
|
| +
|
| +import org.chromium.chrome.R;
|
| +
|
| +import org.chromium.base.ApiCompatibilityUtils;
|
| +
|
| +import java.util.ArrayList;
|
| +
|
| +/**
|
| + * A wrapper class designed to:
|
| + * - consume all touch events. This way the parent view (the FrameLayout ContentView) won't
|
| + * have its onTouchEvent called. If it does, ContentView will process the touch click.
|
| + * We don't want web content responding to clicks on the InfoBars.
|
| + * - allow swapping out of children Views for animations.
|
| + *
|
| + * Once an InfoBar has been hidden and removed from the InfoBarContainer, it cannot be reused
|
| + * because the main panel is discarded after the hiding animation.
|
| + */
|
| +public class ContentWrapperView extends FrameLayout {
|
| + private static final String TAG = "ContentWrapperView";
|
| +
|
| + // Index of the child View that will get swapped out during transitions.
|
| + private static final int CONTENT_INDEX = 0;
|
| +
|
| + private final int mGravity;
|
| + private final boolean mInfoBarsFromTop;
|
| + private final InfoBar mInfoBar;
|
| +
|
| + private View mViewToHide;
|
| + private View mViewToShow;
|
| +
|
| + /**
|
| + * Constructs a ContentWrapperView object.
|
| + * @param context The context to create this View with.
|
| + */
|
| + public ContentWrapperView(Context context, InfoBar infoBar, int backgroundType, View panel,
|
| + boolean infoBarsFromTop) {
|
| + // Set up this ViewGroup.
|
| + super(context);
|
| + mInfoBar = infoBar;
|
| + mGravity = infoBarsFromTop ? Gravity.BOTTOM : Gravity.TOP;
|
| + mInfoBarsFromTop = infoBarsFromTop;
|
| +
|
| + // Pull out resources we need for the backgrounds. Defaults to the INFO type.
|
| + int separatorBackground = R.color.infobar_info_background_separator;
|
| + int layoutBackground = R.drawable.infobar_info_background;
|
| + if (backgroundType == InfoBar.BACKGROUND_TYPE_WARNING) {
|
| + layoutBackground = R.drawable.infobar_warning_background;
|
| + separatorBackground = R.color.infobar_warning_background_separator;
|
| + }
|
| +
|
| + // Set up this view.
|
| + Resources resources = context.getResources();
|
| + LayoutParams wrapParams = new LayoutParams(LayoutParams.MATCH_PARENT,
|
| + LayoutParams.WRAP_CONTENT);
|
| + setLayoutParams(wrapParams);
|
| + ApiCompatibilityUtils.setBackgroundForView(this, resources.getDrawable(layoutBackground));
|
| +
|
| + // Add a separator line that delineates different InfoBars.
|
| + View separator = new View(context);
|
| + separator.setBackgroundColor(resources.getColor(separatorBackground));
|
| + addView(separator, new LayoutParams(LayoutParams.MATCH_PARENT, getBoundaryHeight(context),
|
| + mGravity));
|
| +
|
| + // Add the InfoBar content.
|
| + addChildView(panel);
|
| + }
|
| +
|
| + @Override
|
| + public boolean onInterceptTouchEvent(MotionEvent ev) {
|
| + return !mInfoBar.areControlsEnabled();
|
| + }
|
| +
|
| + @Override
|
| + public boolean onTouchEvent(MotionEvent event) {
|
| + // Consume all motion events so they do not reach the ContentView.
|
| + return true;
|
| + }
|
| +
|
| + /**
|
| + * Calculates how tall the InfoBar boundary should be in pixels.
|
| + * XHDPI devices and above get a double-tall boundary.
|
| + * @return The height of the boundary.
|
| + */
|
| + private int getBoundaryHeight(Context context) {
|
| + float density = context.getResources().getDisplayMetrics().density;
|
| + return density < 2.0f ? 1 : 2;
|
| + }
|
| +
|
| + /**
|
| + * @return the current View representing the InfoBar.
|
| + */
|
| + public boolean hasChildView() {
|
| + // If there's a View that can be replaced, there will be at least two children for the View.
|
| + // One of the Views will always be the InfoBar separator.
|
| + return getChildCount() > 1;
|
| + }
|
| +
|
| + /**
|
| + * Detaches the View currently being shown and returns it for reparenting.
|
| + * @return the View that is currently being shown.
|
| + */
|
| + public View detachCurrentView() {
|
| + assert getChildCount() > 1;
|
| + View view = getChildAt(CONTENT_INDEX);
|
| + removeView(view);
|
| + return view;
|
| + }
|
| +
|
| + /**
|
| + * Adds a View to this layout, before the InfoBar separator.
|
| + * @param viewToAdd The View to add.
|
| + */
|
| + private void addChildView(View viewToAdd) {
|
| + addView(viewToAdd, CONTENT_INDEX, new FrameLayout.LayoutParams(
|
| + LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT, mGravity));
|
| + }
|
| +
|
| + /**
|
| + * Prepares the animation needed to hide the current View and show the new one.
|
| + * @param viewToShow View that will replace the currently shown child of this FrameLayout.
|
| + */
|
| + public void prepareTransition(View viewToShow) {
|
| + assert mViewToHide == null && mViewToShow == null;
|
| +
|
| + // If it exists, the View that is being replaced will be the non-separator child and will
|
| + // we in the second position.
|
| + assert getChildCount() <= 2;
|
| + if (hasChildView()) {
|
| + mViewToHide = getChildAt(CONTENT_INDEX);
|
| + }
|
| +
|
| + mViewToShow = viewToShow;
|
| + assert mViewToHide != null || mViewToShow != null;
|
| + assert mViewToHide != mViewToShow;
|
| + }
|
| +
|
| + /**
|
| + * Called when the animation is starting.
|
| + */
|
| + public void startTransition() {
|
| + if (mViewToShow != null) {
|
| + // Move the View to this container.
|
| + ViewParent parent = mViewToShow.getParent();
|
| + assert parent != null && parent instanceof ViewGroup;
|
| + ((ViewGroup) parent).removeView(mViewToShow);
|
| + addChildView(mViewToShow);
|
| +
|
| + // We're transitioning between two views; set the alpha so it doesn't pop in.
|
| + if (mViewToHide != null) mViewToShow.setAlpha(0.0f);
|
| +
|
| + // Because of layout scheduling, we need to move the child Views downward before it
|
| + // occurs. Failure to do so results in the Views being located incorrectly during the
|
| + // first few frames of the animation.
|
| + if (mInfoBarsFromTop && getViewToShowHeight() > getViewToHideHeight()) {
|
| + getLayoutParams().height = getViewToShowHeight();
|
| +
|
| + int translation = getTransitionHeightDifference();
|
| + for (int i = 0; i < getChildCount(); ++i) {
|
| + View v = getChildAt(i);
|
| + v.setTop(v.getTop() + translation);
|
| + v.setBottom(v.getBottom() + translation);
|
| + }
|
| + }
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Called when the animation is done.
|
| + * At this point, we can get rid of the View that used to represent the InfoBar and re-enable
|
| + * controls.
|
| + */
|
| + public void finishTransition() {
|
| + if (mViewToHide != null) {
|
| + removeView(mViewToHide);
|
| + }
|
| + getLayoutParams().height = ViewGroup.LayoutParams.WRAP_CONTENT;
|
| + requestLayout();
|
| +
|
| + mViewToHide = null;
|
| + mViewToShow = null;
|
| + mInfoBar.setControlsEnabled(true);
|
| + }
|
| +
|
| + /**
|
| + * Returns the height of the View being shown.
|
| + * If no new View is going to replace the current one (i.e. the InfoBar is being hidden), the
|
| + * height is 0.
|
| + */
|
| + private int getViewToShowHeight() {
|
| + return mViewToShow == null ? 0 : mViewToShow.getHeight();
|
| + }
|
| +
|
| + /**
|
| + * Returns the height of the View being hidden.
|
| + * If there wasn't a View in the container (i.e. the InfoBar is being animated onto the screen),
|
| + * then the height is 0.
|
| + */
|
| + private int getViewToHideHeight() {
|
| + return mViewToHide == null ? 0 : mViewToHide.getHeight();
|
| + }
|
| +
|
| + /**
|
| + * @return the difference in height between the View being shown and the View being hidden.
|
| + */
|
| + public int getTransitionHeightDifference() {
|
| + return getViewToShowHeight() - getViewToHideHeight();
|
| + }
|
| +
|
| + /**
|
| + * Creates animations for transitioning between the two Views.
|
| + * @param animators ArrayList to append the transition Animators to.
|
| + */
|
| + public void getAnimationsForTransition(ArrayList<Animator> animators) {
|
| + if (mViewToHide != null && mViewToShow != null) {
|
| + ObjectAnimator hideAnimator;
|
| + hideAnimator = ObjectAnimator.ofFloat((Object)mViewToHide, "alpha", 1.0f, 0.0f);
|
| + animators.add(hideAnimator);
|
| +
|
| + ObjectAnimator showAnimator;
|
| + showAnimator = ObjectAnimator.ofFloat((Object)mViewToShow, "alpha", 0.0f, 1.0f);
|
| + animators.add(showAnimator);
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Calculates a Rect that prevents this ContentWrapperView from overlapping its siblings.
|
| + * Because of the way the InfoBarContainer stores its children, Android will cause the InfoBars
|
| + * to overlap when a bar is slid towards the top of the screen. This calculates a bounding box
|
| + * around this ContentWrapperView that clips the InfoBar to be drawn solely in the space it was
|
| + * occupying before being translated anywhere.
|
| + * @return the calculated bounding box
|
| + */
|
| + public Rect getClippingRect() {
|
| + int maxHeight = Math.max(getViewToHideHeight(), getViewToShowHeight());
|
| + return new Rect(getLeft(), getTop(), getRight(), getTop() + maxHeight);
|
| + }
|
| +}
|
|
|