Index: chrome/android/java/src/org/chromium/chrome/browser/infobar/InfoBarContainerLayout.java |
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/InfoBarContainerLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/InfoBarContainerLayout.java |
index 3dd20bf46d3121aaf6d83826987f453c9efa90a8..f4638c38711f444bf7f2b00cefa7cad6f4e9a8c6 100644 |
--- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/InfoBarContainerLayout.java |
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/InfoBarContainerLayout.java |
@@ -8,12 +8,13 @@ import android.animation.Animator; |
import android.animation.AnimatorListenerAdapter; |
import android.animation.AnimatorSet; |
import android.animation.ObjectAnimator; |
+import android.animation.ValueAnimator; |
+import android.annotation.SuppressLint; |
import android.content.Context; |
+import android.content.res.Resources; |
import android.view.Gravity; |
-import android.view.LayoutInflater; |
import android.view.MotionEvent; |
import android.view.View; |
-import android.view.ViewGroup; |
import android.widget.FrameLayout; |
import org.chromium.chrome.R; |
@@ -58,10 +59,7 @@ import java.util.Collection; |
* Or can we just call setEnabled() false on the infobar wrapper? Will this cause the buttons |
* visual state to change (i.e. to turn gray)? |
* |
- * TODO(newt): finalize animation timings. |
- * |
- * TODO: investigate major lag on Nexus 7 runing KK when tapping e.g. "French" on the translation |
- * infobar to trigger the Change Languages panel. |
+ * TODO(newt): finalize animation timings and interpolators. |
*/ |
class InfoBarContainerLayout extends FrameLayout { |
@@ -99,9 +97,9 @@ class InfoBarContainerLayout extends FrameLayout { |
*/ |
InfoBarContainerLayout(Context context) { |
super(context); |
- setChildrenDrawingOrderEnabled(true); |
- mBackInfobarHeight = context.getResources().getDimensionPixelSize( |
- R.dimen.infobar_peeking_height); |
+ Resources res = context.getResources(); |
+ mBackInfobarHeight = res.getDimensionPixelSize(R.dimen.infobar_peeking_height); |
+ mFloatingBehavior = new FloatingBehavior(this); |
} |
/** |
@@ -200,6 +198,22 @@ class InfoBarContainerLayout extends FrameLayout { |
} |
/** |
+ * Returns an animator that animates an InfoBarWrapper's y-translation from its current |
+ * value to endValue and updates the side shadow positions on each frame. |
+ */ |
+ ValueAnimator createTranslationYAnimator(final InfoBarWrapper wrapper, float endValue) { |
+ ValueAnimator animator = ValueAnimator.ofFloat(wrapper.getTranslationY(), endValue); |
+ animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { |
+ @Override |
+ public void onAnimationUpdate(ValueAnimator animation) { |
+ wrapper.setTranslationY((float) animation.getAnimatedValue()); |
+ mFloatingBehavior.updateShadowPosition(); |
+ } |
+ }); |
+ return animator; |
+ } |
+ |
+ /** |
* Called before the animation begins. This is the time to add views to the hierarchy and |
* adjust layout parameters. |
*/ |
@@ -229,32 +243,30 @@ class InfoBarContainerLayout extends FrameLayout { |
* content fades in. |
*/ |
private class FrontInfoBarAppearingAnimation extends InfoBarAnimation { |
- private ViewGroup mFrontView; |
- private View mFrontInnerView; |
+ private InfoBarWrapper mFrontWrapper; |
+ private View mFrontContents; |
- FrontInfoBarAppearingAnimation(View frontInnerView) { |
- mFrontInnerView = frontInnerView; |
+ FrontInfoBarAppearingAnimation(View frontContents) { |
+ mFrontContents = frontContents; |
} |
@Override |
void prepareAnimation() { |
- mFrontView = (ViewGroup) LayoutInflater.from(getContext()).inflate( |
- R.layout.infobar_wrapper, InfoBarContainerLayout.this, false); |
- addInnerView(mFrontView, mFrontInnerView); |
- addView(mFrontView); |
- updateLayoutParams(); |
+ mFrontWrapper = new InfoBarWrapper(getContext()); |
+ mFrontWrapper.addView(mFrontContents); |
+ addWrapper(mFrontWrapper); |
} |
@Override |
Animator createAnimator() { |
- mFrontView.setTranslationY(mFrontView.getHeight()); |
- mFrontInnerView.setAlpha(0f); |
+ mFrontWrapper.setTranslationY(mFrontWrapper.getHeight()); |
+ mFrontContents.setAlpha(0f); |
AnimatorSet animator = new AnimatorSet(); |
animator.playSequentially( |
- ObjectAnimator.ofFloat(mFrontView, View.TRANSLATION_Y, 0f) |
+ createTranslationYAnimator(mFrontWrapper, 0f) |
.setDuration(DURATION_SLIDE_UP_MS), |
- ObjectAnimator.ofFloat(mFrontInnerView, View.ALPHA, 1f) |
+ ObjectAnimator.ofFloat(mFrontContents, View.ALPHA, 1f) |
.setDuration(DURATION_FADE_MS)); |
return animator; |
} |
@@ -275,20 +287,18 @@ class InfoBarContainerLayout extends FrameLayout { |
* its top edge peeks out just a bit. |
*/ |
private class BackInfoBarAppearingAnimation extends InfoBarAnimation { |
- private View mAppearingView; |
+ private InfoBarWrapper mAppearingWrapper; |
@Override |
void prepareAnimation() { |
- mAppearingView = LayoutInflater.from(getContext()).inflate(R.layout.infobar_wrapper, |
- InfoBarContainerLayout.this, false); |
- addView(mAppearingView); |
- updateLayoutParams(); |
+ mAppearingWrapper = new InfoBarWrapper(getContext()); |
+ addWrapper(mAppearingWrapper); |
} |
@Override |
Animator createAnimator() { |
- mAppearingView.setTranslationY(mAppearingView.getHeight()); |
- return ObjectAnimator.ofFloat(mAppearingView, View.TRANSLATION_Y, 0f) |
+ mAppearingWrapper.setTranslationY(mAppearingWrapper.getHeight()); |
+ return createTranslationYAnimator(mAppearingWrapper, 0f) |
.setDuration(DURATION_SLIDE_UP_MS); |
} |
@@ -304,46 +314,46 @@ class InfoBarContainerLayout extends FrameLayout { |
* new front infobar, and then the new front infobar's contents will fade in. |
*/ |
private class FrontInfoBarDisappearingAndRevealingAnimation extends InfoBarAnimation { |
- private ViewGroup mOldFrontView; |
- private ViewGroup mNewFrontView; |
- private View mNewFrontInnerView; |
+ private InfoBarWrapper mOldFrontWrapper; |
+ private InfoBarWrapper mNewFrontWrapper; |
+ private View mNewFrontContents; |
- FrontInfoBarDisappearingAndRevealingAnimation(View newFrontInnerView) { |
- mNewFrontInnerView = newFrontInnerView; |
+ FrontInfoBarDisappearingAndRevealingAnimation(View newFrontContents) { |
+ mNewFrontContents = newFrontContents; |
} |
@Override |
void prepareAnimation() { |
- mOldFrontView = (ViewGroup) getChildAt(0); |
- mNewFrontView = (ViewGroup) getChildAt(1); |
- addInnerView(mNewFrontView, mNewFrontInnerView); |
+ mOldFrontWrapper = mInfoBarWrappers.get(0); |
+ mNewFrontWrapper = mInfoBarWrappers.get(1); |
+ mNewFrontWrapper.addView(mNewFrontContents); |
} |
@Override |
Animator createAnimator() { |
- // The amount by which mNewFrontView will grow (a negative value indicates shrinking). |
- int deltaHeight = (mNewFrontView.getHeight() - mBackInfobarHeight) |
- - mOldFrontView.getHeight(); |
+ // The amount by which mNewFrontWrapper will grow (negative value indicates shrinking). |
+ int deltaHeight = (mNewFrontWrapper.getHeight() - mBackInfobarHeight) |
+ - mOldFrontWrapper.getHeight(); |
int startTranslationY = Math.max(deltaHeight, 0); |
int endTranslationY = Math.max(-deltaHeight, 0); |
// Slide the front infobar down and away. |
AnimatorSet animator = new AnimatorSet(); |
- mOldFrontView.setTranslationY(startTranslationY); |
- animator.play(ObjectAnimator.ofFloat(mOldFrontView, View.TRANSLATION_Y, |
- startTranslationY + mOldFrontView.getHeight()) |
+ mOldFrontWrapper.setTranslationY(startTranslationY); |
+ animator.play(createTranslationYAnimator(mOldFrontWrapper, |
+ startTranslationY + mOldFrontWrapper.getHeight()) |
.setDuration(DURATION_SLIDE_UP_MS)); |
// Slide the other infobars to their new positions. |
// Note: animator.play() causes these animations to run simultaneously. |
- for (int i = 1; i < getChildCount(); i++) { |
- getChildAt(i).setTranslationY(startTranslationY); |
- animator.play(ObjectAnimator.ofFloat(getChildAt(i), View.TRANSLATION_Y, |
+ for (int i = 1; i < mInfoBarWrappers.size(); i++) { |
+ mInfoBarWrappers.get(i).setTranslationY(startTranslationY); |
+ animator.play(createTranslationYAnimator(mInfoBarWrappers.get(i), |
endTranslationY).setDuration(DURATION_SLIDE_UP_MS)); |
} |
- mNewFrontInnerView.setAlpha(0f); |
- animator.play(ObjectAnimator.ofFloat(mNewFrontInnerView, View.ALPHA, 1f) |
+ mNewFrontContents.setAlpha(0f); |
+ animator.play(ObjectAnimator.ofFloat(mNewFrontContents, View.ALPHA, 1f) |
.setDuration(DURATION_FADE_MS)).after(DURATION_SLIDE_UP_MS); |
return animator; |
@@ -351,12 +361,11 @@ class InfoBarContainerLayout extends FrameLayout { |
@Override |
void onAnimationEnd() { |
- mOldFrontView.removeAllViews(); |
- removeView(mOldFrontView); |
- for (int i = 0; i < getChildCount(); i++) { |
- getChildAt(i).setTranslationY(0); |
+ mOldFrontWrapper.removeAllViews(); |
+ removeWrapper(mOldFrontWrapper); |
+ for (int i = 0; i < mInfoBarWrappers.size(); i++) { |
+ mInfoBarWrappers.get(i).setTranslationY(0); |
} |
- updateLayoutParams(); |
announceForAccessibility(mFrontItem.getAccessibilityText()); |
} |
@@ -371,25 +380,24 @@ class InfoBarContainerLayout extends FrameLayout { |
* The infobar simply slides down out of the container. |
*/ |
private class InfoBarDisappearingAnimation extends InfoBarAnimation { |
- private ViewGroup mDisappearingView; |
+ private InfoBarWrapper mDisappearingWrapper; |
@Override |
void prepareAnimation() { |
- mDisappearingView = (ViewGroup) getChildAt(getChildCount() - 1); |
+ mDisappearingWrapper = mInfoBarWrappers.get(mInfoBarWrappers.size() - 1); |
} |
@Override |
Animator createAnimator() { |
- return ObjectAnimator.ofFloat(mDisappearingView, View.TRANSLATION_Y, |
- mDisappearingView.getHeight()) |
+ return createTranslationYAnimator(mDisappearingWrapper, |
+ mDisappearingWrapper.getHeight()) |
.setDuration(DURATION_SLIDE_DOWN_MS); |
} |
@Override |
void onAnimationEnd() { |
- mDisappearingView.removeAllViews(); |
- removeView(mDisappearingView); |
- updateLayoutParams(); |
+ mDisappearingWrapper.removeAllViews(); |
+ removeWrapper(mDisappearingWrapper); |
} |
@Override |
@@ -403,41 +411,41 @@ class InfoBarContainerLayout extends FrameLayout { |
* then the infobar resizes to fit the new contents, then the new contents fade in. |
*/ |
private class FrontInfoBarSwapContentsAnimation extends InfoBarAnimation { |
- private ViewGroup mFrontView; |
- private View mOldInnerView; |
- private View mNewInnerView; |
+ private InfoBarWrapper mFrontWrapper; |
+ private View mOldContents; |
+ private View mNewContents; |
- FrontInfoBarSwapContentsAnimation(View newInnerView) { |
- mNewInnerView = newInnerView; |
+ FrontInfoBarSwapContentsAnimation(View newContents) { |
+ mNewContents = newContents; |
} |
@Override |
void prepareAnimation() { |
- mFrontView = (ViewGroup) getChildAt(0); |
- mOldInnerView = mFrontView.getChildAt(0); |
- addInnerView(mFrontView, mNewInnerView); |
+ mFrontWrapper = mInfoBarWrappers.get(0); |
+ mOldContents = mFrontWrapper.getChildAt(0); |
+ mFrontWrapper.addView(mNewContents); |
} |
@Override |
Animator createAnimator() { |
- int deltaHeight = mNewInnerView.getHeight() - mOldInnerView.getHeight(); |
+ int deltaHeight = mNewContents.getHeight() - mOldContents.getHeight(); |
InfoBarContainerLayout.this.setTranslationY(Math.max(0, deltaHeight)); |
- mNewInnerView.setAlpha(0f); |
+ mNewContents.setAlpha(0f); |
AnimatorSet animator = new AnimatorSet(); |
animator.playSequentially( |
- ObjectAnimator.ofFloat(mOldInnerView, View.ALPHA, 0f) |
+ ObjectAnimator.ofFloat(mOldContents, View.ALPHA, 0f) |
.setDuration(DURATION_FADE_OUT_MS), |
ObjectAnimator.ofFloat(InfoBarContainerLayout.this, View.TRANSLATION_Y, |
Math.max(0, -deltaHeight)).setDuration(DURATION_SLIDE_UP_MS), |
- ObjectAnimator.ofFloat(mNewInnerView, View.ALPHA, 1f) |
+ ObjectAnimator.ofFloat(mNewContents, View.ALPHA, 1f) |
.setDuration(DURATION_FADE_OUT_MS)); |
return animator; |
} |
@Override |
void onAnimationEnd() { |
- mFrontView.removeViewAt(0); |
+ mFrontWrapper.removeViewAt(0); |
InfoBarContainerLayout.this.setTranslationY(0f); |
mFrontItem.setControlsEnabled(true); |
announceForAccessibility(mFrontItem.getAccessibilityText()); |
@@ -450,6 +458,130 @@ class InfoBarContainerLayout extends FrameLayout { |
} |
/** |
+ * Controls whether infobars fill the full available width, or whether they "float" in the |
+ * middle of the available space. The latter case happens if the available space is wider than |
+ * the max width allowed for infobars. |
+ * |
+ * Also handles the shadows on the sides of the infobars in floating mode. The side shadows are |
+ * separate views -- rather than being part of each InfoBarWrapper -- to avoid a double-shadow |
+ * effect, which would happen during animations when two InfoBarWrappers overlap each other. |
+ */ |
+ private static class FloatingBehavior { |
+ /** The InfoBarContainerLayout. */ |
+ private FrameLayout mLayout; |
+ |
+ /** |
+ * The max width of the infobars. If the available space is wider than this, the infobars |
+ * will switch to floating mode. |
+ */ |
+ private final int mMaxWidth; |
+ |
+ /** The width of the left and right shadows. */ |
+ private final int mShadowWidth; |
+ |
+ /** Whether the layout is currently floating. */ |
+ private boolean mIsFloating; |
+ |
+ /** The shadows that appear on the sides of the infobars in floating mode. */ |
+ private View mLeftShadowView; |
+ private View mRightShadowView; |
+ |
+ FloatingBehavior(FrameLayout layout) { |
+ mLayout = layout; |
+ Resources res = mLayout.getContext().getResources(); |
+ mMaxWidth = res.getDimensionPixelSize(R.dimen.infobar_max_width); |
+ mShadowWidth = res.getDimensionPixelSize(R.dimen.infobar_shadow_width); |
+ } |
+ |
+ /** |
+ * This should be called in onMeasure() before super.onMeasure(). The return value is a new |
+ * widthMeasureSpec that should be passed to super.onMeasure(). |
+ */ |
+ int beforeOnMeasure(int widthMeasureSpec) { |
+ int width = MeasureSpec.getSize(widthMeasureSpec); |
+ boolean isFloating = width > mMaxWidth; |
+ if (isFloating != mIsFloating) { |
+ mIsFloating = isFloating; |
+ onIsFloatingChanged(); |
+ } |
+ |
+ if (isFloating) { |
+ int mode = MeasureSpec.getMode(widthMeasureSpec); |
+ width = Math.min(width, mMaxWidth + 2 * mShadowWidth); |
+ widthMeasureSpec = MeasureSpec.makeMeasureSpec(width, mode); |
+ } |
+ return widthMeasureSpec; |
+ } |
+ |
+ /** |
+ * This should be called in onMeasure() after super.onMeasure(). |
+ */ |
+ void afterOnMeasure(int measuredHeight) { |
+ if (!mIsFloating) return; |
+ // Measure side shadows to match the parent view's height. |
+ int widthSpec = MeasureSpec.makeMeasureSpec(mShadowWidth, MeasureSpec.EXACTLY); |
+ int heightSpec = MeasureSpec.makeMeasureSpec(measuredHeight, MeasureSpec.EXACTLY); |
+ mLeftShadowView.measure(widthSpec, heightSpec); |
+ mRightShadowView.measure(widthSpec, heightSpec); |
+ } |
+ |
+ /** |
+ * This should be called whenever the Y-position of an infobar changes. |
+ */ |
+ void updateShadowPosition() { |
+ if (!mIsFloating) return; |
+ float minY = mLayout.getHeight(); |
+ int childCount = mLayout.getChildCount(); |
+ for (int i = 0; i < childCount; i++) { |
+ View child = mLayout.getChildAt(i); |
+ if (child != mLeftShadowView && child != mRightShadowView) { |
+ minY = Math.min(minY, child.getY()); |
+ } |
+ } |
+ mLeftShadowView.setY(minY); |
+ mRightShadowView.setY(minY); |
+ } |
+ |
+ private void onIsFloatingChanged() { |
+ if (mIsFloating) { |
+ initShadowViews(); |
+ mLayout.setPadding(mShadowWidth, 0, mShadowWidth, 0); |
+ mLayout.setClipToPadding(false); |
+ mLayout.addView(mLeftShadowView); |
+ mLayout.addView(mRightShadowView); |
+ } else { |
+ mLayout.setPadding(0, 0, 0, 0); |
+ mLayout.removeView(mLeftShadowView); |
+ mLayout.removeView(mRightShadowView); |
+ } |
+ } |
+ |
+ @SuppressLint("RtlHardcoded") |
+ private void initShadowViews() { |
+ if (mLeftShadowView != null) return; |
+ |
+ mLeftShadowView = new View(mLayout.getContext()); |
+ mLeftShadowView.setBackgroundResource(R.drawable.infobar_shadow_left); |
+ LayoutParams leftLp = new FrameLayout.LayoutParams(0, 0, Gravity.LEFT); |
+ leftLp.leftMargin = -mShadowWidth; |
+ mLeftShadowView.setLayoutParams(leftLp); |
+ |
+ mRightShadowView = new View(mLayout.getContext()); |
+ mRightShadowView.setBackgroundResource(R.drawable.infobar_shadow_left); |
+ LayoutParams rightLp = new FrameLayout.LayoutParams(0, 0, Gravity.RIGHT); |
+ rightLp.rightMargin = -mShadowWidth; |
+ mRightShadowView.setScaleX(-1f); |
+ mRightShadowView.setLayoutParams(rightLp); |
+ } |
+ } |
+ |
+ /** |
+ * The height of back infobars, i.e. the distance between the top of the front infobar and the |
+ * top of the next infobar back. |
+ */ |
+ private final int mBackInfobarHeight; |
+ |
+ /** |
* All the Items, in front to back order. |
* This list is updated immediately when addInfoBar(), removeInfoBar(), and swapInfoBar() are |
* called; so during animations, it does *not* match the currently visible views. |
@@ -462,16 +594,17 @@ class InfoBarContainerLayout extends FrameLayout { |
*/ |
private Item mFrontItem; |
+ /** |
+ * The list of InfoBarWrapper views that are currently visible. |
+ */ |
+ private final ArrayList<InfoBarWrapper> mInfoBarWrappers = new ArrayList<>(); |
+ |
/** The current animation, or null if no animation is happening currently. */ |
private InfoBarAnimation mAnimation; |
private InfoBarAnimationListener mAnimationListener; |
- /** |
- * The height of back infobars, i.e. the distance between the top of the front infobar and the |
- * top of the next infobar back. |
- */ |
- private int mBackInfobarHeight; |
+ private FloatingBehavior mFloatingBehavior; |
/** |
* Determines whether any animations need to run in order to make the visible views match the |
@@ -485,7 +618,7 @@ class InfoBarContainerLayout extends FrameLayout { |
// removals happen before additions or swaps, and changes are made to back infobars before |
// front infobars. |
- int childCount = getChildCount(); |
+ int childCount = mInfoBarWrappers.size(); |
int desiredChildCount = Math.min(mItems.size(), MAX_STACK_DEPTH); |
boolean shouldRemoveFrontView = mFrontItem != null && !mItems.contains(mFrontItem); |
@@ -513,8 +646,8 @@ class InfoBarContainerLayout extends FrameLayout { |
// Third, run swap animation on front infobar if needed. |
if (mFrontItem != null && mItems.contains(mFrontItem)) { |
- View frontInnerView = ((ViewGroup) getChildAt(0)).getChildAt(0); |
- if (frontInnerView != mFrontItem.getView()) { |
+ View frontContents = mInfoBarWrappers.get(0).getChildAt(0); |
+ if (frontContents != mFrontItem.getView()) { |
runAnimation(new FrontInfoBarSwapContentsAnimation(mFrontItem.getView())); |
return; |
} |
@@ -543,19 +676,23 @@ class InfoBarContainerLayout extends FrameLayout { |
} |
} |
- /** |
- * Adds an infobar view to a wrapper view, with suitable LayoutParams. |
- */ |
- private void addInnerView(ViewGroup wrapperView, View innerView) { |
- wrapperView.addView(innerView, new LayoutParams( |
- LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT, Gravity.TOP)); |
+ private void addWrapper(InfoBarWrapper wrapper) { |
+ addView(wrapper, 0, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)); |
+ mInfoBarWrappers.add(wrapper); |
+ updateLayoutParams(); |
+ } |
+ |
+ private void removeWrapper(InfoBarWrapper wrapper) { |
+ removeView(wrapper); |
+ mInfoBarWrappers.remove(wrapper); |
+ updateLayoutParams(); |
} |
private void updateLayoutParams() { |
// Stagger the top margins so the back infobars peek out a bit. |
- int childCount = getChildCount(); |
+ int childCount = mInfoBarWrappers.size(); |
for (int i = 0; i < childCount; i++) { |
- View child = getChildAt(i); |
+ View child = mInfoBarWrappers.get(i); |
LayoutParams lp = (LayoutParams) child.getLayoutParams(); |
lp.topMargin = (childCount - 1 - i) * mBackInfobarHeight; |
child.setLayoutParams(lp); |
@@ -563,8 +700,16 @@ class InfoBarContainerLayout extends FrameLayout { |
} |
@Override |
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { |
+ widthMeasureSpec = mFloatingBehavior.beforeOnMeasure(widthMeasureSpec); |
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec); |
+ mFloatingBehavior.afterOnMeasure(getMeasuredHeight()); |
+ } |
+ |
+ @Override |
protected void onLayout(boolean changed, int left, int top, int right, int bottom) { |
super.onLayout(changed, left, top, right, bottom); |
+ mFloatingBehavior.updateShadowPosition(); |
// Animations start after a layout has completed, at which point all views are guaranteed |
// to have valid sizes and positions. |
@@ -574,13 +719,6 @@ class InfoBarContainerLayout extends FrameLayout { |
} |
@Override |
- protected int getChildDrawingOrder(int childCount, int i) { |
- // Draw children from last to first. This allows us to order the children from front to |
- // back, which simplifies the logic elsewhere in this class. |
- return childCount - i - 1; |
- } |
- |
- @Override |
public boolean onInterceptTouchEvent(MotionEvent ev) { |
// Trap any attempts to fiddle with the infobars while we're animating. |
return super.onInterceptTouchEvent(ev) || mAnimation != null |