Commit 58394da4 authored by mdjones's avatar mdjones Committed by Commit bot

Peek new infobars behind existing ones

This change extends the peeking behavior when there are multiple
infobars attempting to show simultaneously. When a new infobar is
added, it will peek above the existing ones giving a brief view of
it's contents and bringing more attention to it.

BUG=721389

Review-Url: https://codereview.chromium.org/2846663002
Cr-Commit-Position: refs/heads/master@{#473719}
parent c8de6a53
......@@ -15,6 +15,8 @@ import android.content.res.Resources;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.FrameLayout;
import org.chromium.base.ObserverList;
......@@ -22,6 +24,7 @@ import org.chromium.chrome.R;
import org.chromium.chrome.browser.infobar.InfoBarContainer.InfoBarAnimationListener;
import java.util.ArrayList;
import java.util.List;
/**
* Layout that displays infobars in a stack. Handles all the animations when adding or removing
......@@ -112,6 +115,15 @@ public class InfoBarContainerLayout extends FrameLayout {
Resources res = context.getResources();
mBackInfobarHeight = res.getDimensionPixelSize(R.dimen.infobar_peeking_height);
mFloatingBehavior = new FloatingBehavior(this);
mBackgroundPeekSize = getResources().getDimensionPixelSize(R.dimen.infobar_compact_size);
mInfoBarShadowHeight = getResources().getDimensionPixelSize(R.dimen.infobar_shadow_height);
}
@Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
mBottomContainer = (ViewGroup) getRootView().findViewById(R.id.bottom_container);
}
/**
......@@ -175,10 +187,20 @@ public class InfoBarContainerLayout extends FrameLayout {
// Animation durations.
private static final int DURATION_SLIDE_UP_MS = 250;
private static final int DURATION_PEEK_MS = 500;
private static final int DURATION_SLIDE_DOWN_MS = 250;
private static final int DURATION_FADE_MS = 100;
private static final int DURATION_FADE_OUT_MS = 200;
/** The height that an infobar will peek when being added behind another one. */
private final int mBackgroundPeekSize;
/** The height of the shadow that sits above the infobar. */
private final int mInfoBarShadowHeight;
/** The bottom container that the infobar container sits inside of. */
private ViewGroup mBottomContainer;
/**
* Base class for animations inside the InfoBarContainerLayout.
*
......@@ -215,11 +237,10 @@ public class InfoBarContainerLayout extends FrameLayout {
* 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);
ValueAnimator animator = ObjectAnimator.ofFloat(wrapper, View.TRANSLATION_Y, endValue);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
wrapper.setTranslationY((float) animation.getAnimatedValue());
mFloatingBehavior.updateShadowPosition();
}
});
......@@ -407,9 +428,39 @@ public class InfoBarContainerLayout extends FrameLayout {
@Override
Animator createAnimator() {
AnimatorSet set = new AnimatorSet();
List<Animator> animators = new ArrayList<>();
mAppearingWrapper.setTranslationY(mAppearingWrapper.getHeight());
return createTranslationYAnimator(mAppearingWrapper, 0f)
.setDuration(DURATION_SLIDE_UP_MS);
mAppearingWrapper.setRestrictHeightForAnimation(true);
mAppearingWrapper.setHeightForAnimation(mInfoBarShadowHeight + mBackgroundPeekSize);
mAppearingWrapper.addView(mAppearingWrapper.getItem().getView());
ValueAnimator animator = createTranslationYAnimator(
mAppearingWrapper, mBackInfobarHeight - mBackgroundPeekSize);
animators.add(animator);
animators.add(createTranslationYAnimator(mAppearingWrapper, 0));
// When the infobar container is running this specific animation, do not clip the
// children so the infobars can animate outside their container.
set.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
setHierarchyClipsChildren(false);
}
@Override
public void onAnimationEnd(Animator animation) {
mAppearingWrapper.setRestrictHeightForAnimation(false);
mAppearingWrapper.removeView(mAppearingWrapper.getItem().getView());
setHierarchyClipsChildren(true);
}
});
set.playSequentially(animators);
set.setDuration(DURATION_PEEK_MS);
return set;
}
@Override
......@@ -418,6 +469,17 @@ public class InfoBarContainerLayout extends FrameLayout {
}
}
/**
* Used to set the relevant view hierarchy to not clip its children. This is used during
* animation so views can draw outside the normal bounds.
* @param clip Whether or not to clip child views.
*/
private void setHierarchyClipsChildren(boolean clip) {
setClipChildren(clip);
((ViewGroup) getParent()).setClipChildren(clip);
mBottomContainer.setClipChildren(clip);
}
/**
* The animation to hide the front infobar and reveal the second-to-front infobar. The front
* infobar slides down and off the screen. The back infobar(s) will adjust to the size of the
......@@ -837,7 +899,10 @@ public class InfoBarContainerLayout extends FrameLayout {
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
widthMeasureSpec = mFloatingBehavior.beforeOnMeasure(widthMeasureSpec);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mFloatingBehavior.afterOnMeasure(getMeasuredHeight());
// Make sure the shadow is tall enough to compensate for the peek animation of other
// infboars.
mFloatingBehavior.afterOnMeasure(getMeasuredHeight() + mBackgroundPeekSize);
}
@Override
......
......@@ -19,6 +19,15 @@ class InfoBarWrapper extends FrameLayout {
private final InfoBarContainerLayout.Item mItem;
/** Whether or not the height of the layout should be restricted for animations. */
private boolean mRestrictHeightForAnimation;
/**
* The height in px that this view will be restricted to if
* {@link #mRestrictHeightForAnimation} is set.
*/
private int mHeightForAnimationPx;
/**
* Constructor for inflating from Java.
*/
......@@ -33,12 +42,38 @@ class InfoBarWrapper extends FrameLayout {
// setBackgroundResource() changes the padding, so call setPadding() second.
setBackgroundResource(R.drawable.infobar_wrapper_bg);
setPadding(0, shadowHeight, 0, 0);
setClipChildren(true);
}
/**
* @param restrict Whether or not the height of this view should be restricted for animations.
*/
public void setRestrictHeightForAnimation(boolean restrict) {
mRestrictHeightForAnimation = restrict;
}
/**
* @param heightPx The restricted height in px that will be used if
* {@link #mRestrictHeightForAnimation} is set.
*/
public void setHeightForAnimation(int heightPx) {
mHeightForAnimationPx = heightPx;
}
InfoBarContainerLayout.Item getItem() {
return mItem;
}
@Override
public void onMeasure(int widthSpec, int heightSpec) {
if (mRestrictHeightForAnimation) {
int heightPx = Math.min(mHeightForAnimationPx, MeasureSpec.getSize(heightSpec));
heightSpec = MeasureSpec.makeMeasureSpec(heightPx, MeasureSpec.getMode(heightSpec));
}
super.onMeasure(widthSpec, heightSpec);
}
@Override
public void onViewAdded(View child) {
child.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT,
......
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