Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3665)

Unified Diff: chrome/android/java/src/org/chromium/chrome/browser/infobar/AnimationHelper.java

Issue 24109002: [InfoBar] Upstram basic infobar flow for Android. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@upstream_infobar_full
Patch Set: Fix License header in two more files Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/android/java/src/org/chromium/chrome/browser/infobar/AnimationHelper.java
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/AnimationHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/AnimationHelper.java
new file mode 100644
index 0000000000000000000000000000000000000000..931772af56d15ecc39e9ecdbfa5f3bdbce0344ed
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/AnimationHelper.java
@@ -0,0 +1,244 @@
+// 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.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
+import android.view.View;
+import android.view.ViewTreeObserver;
+import android.view.animation.AccelerateDecelerateInterpolator;
+
+import org.chromium.base.ApiCompatibilityUtils;
+
+import java.util.ArrayList;
+
+/**
+ * Sets up animations to move InfoBars around inside of the InfoBarContainer.
+ *
+ * Animations proceed in several phases:
+ * 1) Prep work is done for the InfoBar so that the View being animated in (if it exists) is
+ * properly sized. This involves adding the View to a FrameLayout with a visibility of
+ * INVISIBLE and triggering a layout.
+ *
+ * 2) Once the View has an actual size, we compute all of the actions needed for the animation.
+ * We use translations primarily to slide things in and out of the screen as things are shown,
+ * hidden, or resized.
+ *
+ * 3) The animation is kicked off and the animations run. During this phase, the View being shown
+ * is added to ContentWrapperView.
+ *
+ * 4) At the end of the animation, we clean up everything and make sure all the children are in the
+ * right places.
+ */
+public class AnimationHelper implements ViewTreeObserver.OnGlobalLayoutListener {
+ private static final String TAG = "AnimationHelper";
+
+ private static final long ANIMATION_DURATION_MS = 250;
+
+ public static final int ANIMATION_TYPE_SHOW = 0;
+ public static final int ANIMATION_TYPE_SWAP = 1;
+ public static final int ANIMATION_TYPE_HIDE = 2;
+ public static final int ANIMATION_TYPE_BOUNDARY = 3;
+
+ private final InfoBarContainer mContainer;
+ private final InfoBar mInfoBar;
+ private final ContentWrapperView mTargetWrapperView;
+ private final AnimatorSet mAnimatorSet;
+ private final int mAnimationType;
+ private final View mToShow;
+
+ private boolean mAnimationStarted;
+
+ /**
+ * Creates and starts an animation.
+ * @param container InfoBarContainer that is having its InfoBars animated.
+ * @param target ContentWrapperView that is the focus of the animation and is being resized,
+ * shown, or hidden.
+ * @param infoBar InfoBar that goes with the specified ContentWrapperView.
+ * @param toShow If non-null, this View will replace whatever child View the ContentWrapperView
+ * is currently displaying.
+ * @param aniamtionType Type of animation being performed.
+ */
+ public AnimationHelper(InfoBarContainer container, ContentWrapperView target, InfoBar infoBar,
+ View toShow, int animationType) {
+ mContainer = container;
+ mInfoBar = infoBar;
+ mTargetWrapperView = target;
+ mAnimatorSet = new AnimatorSet();
+ mAnimationType = animationType;
+ mToShow = toShow;
+ assert mContainer.indexOfChild(mTargetWrapperView) != -1;
+ }
+
+ /**
+ * Start the animation.
+ */
+ public void start() {
+ mTargetWrapperView.prepareTransition(mToShow);
+ mContainer.prepareTransition(mToShow);
+
+ if (mToShow == null) {
+ // We've got a size already; start the animation immediately.
+ continueAnimation();
+ } else {
+ // Wait for the object to be sized.
+ mTargetWrapperView.getViewTreeObserver().addOnGlobalLayoutListener(this);
+ }
+ }
+
+ /**
+ * @return the InfoBar being animated.
+ */
+ public InfoBar getInfoBar() {
+ return mInfoBar;
+ }
+
+ /**
+ * @return the ContentWrapperView being animated.
+ */
+ public ContentWrapperView getTarget() {
+ return mTargetWrapperView;
+ }
+
+ /**
+ * @return the type of animation being performed.
+ */
+ public int getAnimationType() {
+ return mAnimationType;
+ }
+
+ /**
+ * Catch when the layout occurs, which lets us know when the View has been sized properly.
+ */
+ @Override
+ public void onGlobalLayout() {
+ ApiCompatibilityUtils.removeOnGlobalLayoutListener(mTargetWrapperView, this);
+ continueAnimation();
+ }
+
+ private void continueAnimation() {
+ if (mAnimationStarted) return;
+ mAnimationStarted = true;
+
+ boolean infoBarsOnTop = mContainer.areInfoBarsOnTop();
+ int indexOfWrapperView = mContainer.indexOfChild(mTargetWrapperView);
+ assert indexOfWrapperView != -1;
+
+ ArrayList<Animator> animators = new ArrayList<Animator>();
+ mTargetWrapperView.getAnimationsForTransition(animators);
+
+ // Determine where the tops of each InfoBar will need to be.
+ int heightDifference = mTargetWrapperView.getTransitionHeightDifference();
+ int cumulativeTopStart = 0;
+ int cumulativeTopEnd = 0;
+ int cumulativeEndHeight = 0;
+ if (!infoBarsOnTop) {
+ if (heightDifference >= 0) {
+ // The current container is smaller than the final container, so the current 0
+ // coordinate will be >= 0 in the final container.
+ cumulativeTopStart = heightDifference;
+ } else {
+ // The current container is bigger than the final container, so the current 0
+ // coordinate will be < 0 in the final container.
+ cumulativeTopEnd = -heightDifference;
+ }
+ }
+
+ for (int i = 0; i < mContainer.getChildCount(); ++i) {
+ View view = mContainer.getChildAt(i);
+
+ // At this point, the View being transitioned in shouldn't have been added to the
+ // visible container, yet, and shouldn't affect calculations.
+ int startHeight = view.getHeight();
+ int endHeight = startHeight + (i == indexOfWrapperView ? heightDifference : 0);
+ int topStart = cumulativeTopStart;
+ int topEnd = cumulativeTopEnd;
+ int bottomStart = topStart + startHeight;
+ int bottomEnd = topEnd + endHeight;
+
+ if (topStart == topEnd && bottomStart == bottomEnd) {
+ // The View needs to stay put.
+ view.setTop(topEnd);
+ view.setBottom(bottomEnd);
+ view.setY(topEnd);
+ view.setTranslationY(0);
+ } else {
+ // A translation is required to move the View into place.
+ int translation = heightDifference;
+ if (infoBarsOnTop) translation *= -1;
+
+ boolean translateDownward = false;
+ if (topStart < topEnd) {
+ translateDownward = infoBarsOnTop;
+ } else if (topStart > topEnd) {
+ translateDownward = !infoBarsOnTop;
+ } else {
+ translateDownward = bottomEnd > bottomStart;
+ }
+
+ PropertyValuesHolder viewTranslation;
+ if (translateDownward) {
+ view.setTop(topEnd);
+ view.setBottom(bottomEnd);
+ view.setTranslationY(translation);
+ view.setY(topEnd + translation);
+ viewTranslation =
+ PropertyValuesHolder.ofFloat("translationY", translation, 0.0f);
+ } else {
+ viewTranslation =
+ PropertyValuesHolder.ofFloat("translationY", 0.0f, -translation);
+ }
+
+ animators.add(ObjectAnimator.ofPropertyValuesHolder(view, viewTranslation));
+ }
+
+ // Add heights to the cumulative totals.
+ cumulativeTopStart += startHeight;
+ cumulativeTopEnd += endHeight;
+ cumulativeEndHeight += endHeight;
+ }
+
+ // Lock the InfoBarContainer's size at its largest during the animation to avoid
+ // clipping issues.
+ final int oldContainerTop = mContainer.getTop();
+ final int oldContainerBottom = mContainer.getBottom();
+ final int newContainerTop;
+ final int newContainerBottom;
+ if (infoBarsOnTop) {
+ newContainerTop = oldContainerTop;
+ newContainerBottom = newContainerTop + cumulativeEndHeight;
+ } else {
+ newContainerBottom = oldContainerBottom;
+ newContainerTop = newContainerBottom - cumulativeEndHeight;
+ }
+ final int biggestContainerTop = Math.min(oldContainerTop, newContainerTop);
+ final int biggestContainerBottom = Math.max(oldContainerBottom, newContainerBottom);
+ mContainer.setTop(biggestContainerTop);
+ mContainer.setBottom(biggestContainerBottom);
+
+ // Set up and run all of the animations.
+ mAnimatorSet.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mTargetWrapperView.startTransition();
+ mContainer.startTransition();
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mTargetWrapperView.finishTransition();
+ mContainer.finishTransition();
+ }
+ });
+
+ mAnimatorSet.playTogether(animators);
+ mAnimatorSet.setDuration(ANIMATION_DURATION_MS);
+ mAnimatorSet.setInterpolator(new AccelerateDecelerateInterpolator());
+ mAnimatorSet.start();
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698