<!-- The minimum amount of top overscroll to go to the quick settings. -->
<dimen name="min_top_overscroll_to_qs">36dp</dimen>
- <!-- The padding to the second card when the notifications collapse. -->
- <dimen name="notification_collapse_second_card_padding">8dp</dimen>
-
<!-- The height of the speed bump view. -->
<dimen name="speed_bump_height">16dp</dimen>
= new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
- mAnimate = true;
+ // We need to post since we don't want the notification to animate on the very first
+ // frame
+ post(new Runnable() {
+ @Override
+ public void run() {
+ mAnimate = true;
+ }
+ });
getViewTreeObserver().removeOnPreDrawListener(this);
return true;
}
// In Shade, interpolate linearly such that QS is closed whenever panel height is
// minimum QS expansion + minStackHeight
float panelHeightQsCollapsed = mNotificationStackScroller.getIntrinsicPadding()
- + mNotificationStackScroller.getMinStackHeight();
+ + mNotificationStackScroller.getLayoutMinHeight();
float panelHeightQsExpanded = calculatePanelHeightQsExpanded();
t = (expandedHeight - panelHeightQsCollapsed)
/ (panelHeightQsExpanded - panelHeightQsCollapsed);
&& mShadeEmpty) {
notificationHeight = mNotificationStackScroller.getEmptyShadeViewHeight()
+ mNotificationStackScroller.getBottomStackPeekSize()
- + mNotificationStackScroller.getCollapseSecondCardPadding();
+ + mNotificationStackScroller.getBottomStackSlowDownHeight();
}
int maxQsHeight = mQsMaxExpansionHeight;
+ notificationHeight;
if (totalHeight > mNotificationStackScroller.getHeight()) {
float fullyCollapsedHeight = maxQsHeight
- + mNotificationStackScroller.getMinStackHeight();
+ + mNotificationStackScroller.getLayoutMinHeight();
totalHeight = Math.max(fullyCollapsedHeight, mNotificationStackScroller.getHeight());
}
return (int) totalHeight;
private float getFadeoutAlpha() {
float alpha = (getNotificationsTopY() + mNotificationStackScroller.getFirstItemMinHeight())
/ (mQsMinExpansionHeight + mNotificationStackScroller.getBottomStackPeekSize()
- - mNotificationStackScroller.getCollapseSecondCardPadding());
+ - mNotificationStackScroller.getBottomStackSlowDownHeight());
alpha = Math.max(0, Math.min(alpha, 1));
alpha = (float) Math.pow(alpha, 0.75);
return alpha;
.getDimensionPixelSize(R.dimen.notification_divider_height));
mIncreasedPaddingBetweenElements = context.getResources()
.getDimensionPixelSize(R.dimen.notification_divider_height_increased);
-
mBottomStackSlowDownHeight = mStackScrollAlgorithm.getBottomStackSlowDownLength();
mMinTopOverScrollToEscape = getResources().getDimensionPixelSize(
R.dimen.min_top_overscroll_to_qs);
- mCollapseSecondCardPadding = getResources().getDimensionPixelSize(
- R.dimen.notification_collapse_second_card_padding);
}
private void notifyHeightChangeListener(ExpandableView view) {
}
/**
- * @return whether the height of the layout needs to be adapted, in order to ensure that the
- * last child is not in the bottom stack.
- */
- private boolean needsHeightAdaption() {
- return getNotGoneChildCount() > 1;
- }
-
- /**
* Updates the children views according to the stack scroll algorithm. Call this whenever
* modifications to {@link #mOwnScrollY} are performed to reflect it in the view layout.
*/
mLastSetStackHeight = height;
setIsExpanded(height > 0.0f);
int newStackHeight = (int) height;
- int minStackHeight = getMinStackHeight();
+ int minStackHeight = getLayoutMinHeight();
int stackHeight;
float paddingOffset;
boolean trackingHeadsUp = mTrackingHeadsUp || mHeadsUpManager.hasPinnedHeadsUp();
stackHeight = newStackHeight;
} else {
int translationY;
- if (!trackingHeadsUp) {
- // We did not reach the position yet where we actually start growing,
- // so we translate the stack upwards.
- translationY = (newStackHeight - minStackHeight);
- // A slight parallax effect is introduced in order for the stack to catch up with
- // the top card.
- float partiallyThere = (newStackHeight - mTopPadding - mTopPaddingOverflow)
- / minStackHeight;
- partiallyThere = Math.max(0, partiallyThere);
- translationY += (1 - partiallyThere) * (mBottomStackPeekSize +
- mCollapseSecondCardPadding);
- } else {
- translationY = (int) (height - normalUnfoldPositionStart);
- }
+ translationY = newStackHeight - normalUnfoldPositionStart;
paddingOffset = translationY - mTopPadding;
stackHeight = (int) (height - (translationY - mTopPadding));
}
return mBottomStackPeekSize;
}
- public int getCollapseSecondCardPadding() {
- return mCollapseSecondCardPadding;
+ public int getBottomStackSlowDownHeight() {
+ return mBottomStackSlowDownHeight;
}
public void setLongPressListener(SwipeHelper.LongPressListener listener) {
boolean ignoreIntrinsicPadding) {
float start = qsHeight;
float stackHeight = getHeight() - start;
- int minStackHeight = getMinStackHeight();
+ int minStackHeight = getLayoutMinHeight();
if (stackHeight <= minStackHeight) {
float overflow = minStackHeight - stackHeight;
stackHeight = minStackHeight;
setStackHeight(mLastSetStackHeight);
}
- public int getMinStackHeight() {
+ public int getLayoutMinHeight() {
final ExpandableView firstChild = getFirstChildNotGone();
- final int firstChildMinHeight = firstChild != null ? firstChild.getMinHeight()
+ int firstChildMinHeight = firstChild != null
+ ? firstChild.getIntrinsicHeight()
: mCollapsedSize;
- return firstChildMinHeight + mBottomStackPeekSize + mCollapseSecondCardPadding;
+ if (mOwnScrollY > 0) {
+ firstChildMinHeight = Math.max(firstChildMinHeight - mOwnScrollY, mCollapsedSize);
+ }
+ return Math.min(firstChildMinHeight + mBottomStackPeekSize + mBottomStackSlowDownHeight,
+ mMaxLayoutHeight - mTopPadding);
}
public float getTopPaddingOverflow() {
final int firstChildMinHeight = firstChild != null ? (int) firstChild.getMinHeight()
: mCollapsedSize;
return mIntrinsicPadding + firstChildMinHeight + mBottomStackPeekSize
- + mCollapseSecondCardPadding;
+ + mBottomStackSlowDownHeight;
}
private int clampPadding(int desiredPadding) {
}
private void onViewRemovedInternal(View child) {
- mStackScrollAlgorithm.notifyChildrenChanged(this);
if (mChangePositionInProgress) {
// This is only a position change, don't do anything special
return;
private void onViewAddedInternal(View child) {
updateHideSensitiveForChild(child);
- mStackScrollAlgorithm.notifyChildrenChanged(this);
((ExpandableView) child).setOnHeightChangedListener(this);
generateAddAnimation(child, false /* fromMoreCard */);
updateAnimationState(child);
}
public int getEmptyBottomMargin() {
- int emptyMargin = mMaxLayoutHeight - mContentHeight - mBottomStackPeekSize;
- if (needsHeightAdaption()) {
- emptyMargin -= mBottomStackSlowDownHeight;
- } else {
- emptyMargin -= mCollapseSecondCardPadding;
- }
+ int emptyMargin = mMaxLayoutHeight - mContentHeight - mBottomStackPeekSize
+ - mBottomStackSlowDownHeight;
return Math.max(emptyMargin, 0);
}
public void onExpansionStarted() {
mIsExpansionChanging = true;
- mStackScrollAlgorithm.onExpansionStarted(mCurrentStackScrollState);
}
public void onExpansionStopped() {
mIsExpansionChanging = false;
- mStackScrollAlgorithm.onExpansionStopped();
if (!mIsExpanded) {
mOwnScrollY = 0;
if (mIsExpanded && mAnimationsEnabled) {
mRequestViewResizeAnimationOnLayout = true;
}
- mStackScrollAlgorithm.onReset(view);
updateAnimationState(view);
updateChronometerForChild(view);
}
}
public int getDismissViewHeight() {
- int height = mDismissView.getHeight() + mPaddingBetweenElements;
-
- // Hack: Accommodate for additional distance when we only have one notification and the
- // dismiss all button.
- if (getNotGoneChildCount() == 2 && getLastChildNotGone() == mDismissView
- && getFirstChildNotGone() instanceof ActivatableNotificationView) {
- height += mCollapseSecondCardPadding;
- }
- return height;
+ return mDismissView.getHeight() + mPaddingBetweenElements;
}
public int getEmptyShadeViewHeight() {
private StackIndentationFunctor mBottomStackIndentationFunctor;
private StackScrollAlgorithmState mTempAlgorithmState = new StackScrollAlgorithmState();
- private boolean mIsExpansionChanging;
- private int mFirstChildMaxHeight;
private boolean mIsExpanded;
- private ExpandableView mFirstChildWhileExpanding;
- private boolean mExpandedOnStart;
private int mBottomStackSlowDownLength;
- private int mCollapseSecondCardPadding;
public StackScrollAlgorithm(Context context) {
initView(context);
mZBasicHeight = (MAX_ITEMS_IN_BOTTOM_STACK + 1) * mZDistanceBetweenElements;
mBottomStackSlowDownLength = context.getResources()
.getDimensionPixelSize(R.dimen.bottom_stack_slow_down_length);
- mCollapseSecondCardPadding = context.getResources().getDimensionPixelSize(
- R.dimen.notification_collapse_second_card_padding);
mBottomStackIndentationFunctor = new PiecewiseLinearIndentationFunctor(
MAX_ITEMS_IN_BOTTOM_STACK,
mBottomStackPeekSize,
int childHeight, int minHeight, AmbientState ambientState) {
int bottomStackStart = ambientState.getInnerHeight()
- - mBottomStackPeekSize - mCollapseSecondCardPadding;
+ - mBottomStackPeekSize - mBottomStackSlowDownLength;
int childStart = bottomStackStart - childHeight;
if (childStart < childViewState.yTranslation) {
float newHeight = bottomStackStart - childViewState.yTranslation;
// The starting position of the bottom stack peek
int bottomPeekStart = ambientState.getInnerHeight() - mBottomStackPeekSize -
- mCollapseSecondCardPadding + ambientState.getScrollY();
+ mBottomStackSlowDownLength + ambientState.getScrollY();
// Collapse and expand the first child while the shade is being expanded
- float maxHeight = mIsExpansionChanging && child == mFirstChildWhileExpanding
- ? mFirstChildMaxHeight
- : childHeight;
- childViewState.height = (int) Math.max(Math.min(bottomPeekStart, maxHeight),
+ childViewState.height = (int) Math.max(Math.min(bottomPeekStart, (float) childHeight),
child.getMinHeight());
}
}
}
- public void onExpansionStarted(StackScrollState currentState) {
- mIsExpansionChanging = true;
- mExpandedOnStart = mIsExpanded;
- ViewGroup hostView = currentState.getHostView();
- updateFirstChildHeightWhileExpanding(hostView);
- }
-
- private void updateFirstChildHeightWhileExpanding(ViewGroup hostView) {
- mFirstChildWhileExpanding = (ExpandableView) findFirstVisibleChild(hostView);
- if (mFirstChildWhileExpanding != null) {
- if (mExpandedOnStart) {
-
- // We are collapsing the shade, so the first child can get as most as high as the
- // current height or the end value of the animation.
- mFirstChildMaxHeight = StackStateAnimator.getFinalActualHeight(
- mFirstChildWhileExpanding);
- } else {
- updateFirstChildMaxSizeToMaxHeight();
- }
- } else {
- mFirstChildMaxHeight = 0;
- }
- }
-
- private void updateFirstChildMaxSizeToMaxHeight() {
- // We are expanding the shade, expand it to its full height.
- if (!isMaxSizeInitialized(mFirstChildWhileExpanding)) {
-
- // This child was not layouted yet, wait for a layout pass
- mFirstChildWhileExpanding
- .addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
- @Override
- public void onLayoutChange(View v, int left, int top, int right,
- int bottom, int oldLeft, int oldTop, int oldRight,
- int oldBottom) {
- if (mFirstChildWhileExpanding != null) {
- mFirstChildMaxHeight = getMaxAllowedChildHeight(
- mFirstChildWhileExpanding);
- } else {
- mFirstChildMaxHeight = 0;
- }
- v.removeOnLayoutChangeListener(this);
- }
- });
- } else {
- mFirstChildMaxHeight = getMaxAllowedChildHeight(mFirstChildWhileExpanding);
- }
- }
-
private boolean isMaxSizeInitialized(ExpandableView child) {
if (child instanceof ExpandableNotificationRow) {
ExpandableNotificationRow row = (ExpandableNotificationRow) child;
return null;
}
- public void onExpansionStopped() {
- mIsExpansionChanging = false;
- mFirstChildWhileExpanding = null;
- }
-
public void setIsExpanded(boolean isExpanded) {
this.mIsExpanded = isExpanded;
}
- public void notifyChildrenChanged(final NotificationStackScrollLayout hostView) {
- if (mIsExpansionChanging) {
- hostView.post(new Runnable() {
- @Override
- public void run() {
- updateFirstChildHeightWhileExpanding(hostView);
- }
- });
- }
- }
-
- public void onReset(ExpandableView view) {
- if (view.equals(mFirstChildWhileExpanding)) {
- updateFirstChildMaxSizeToMaxHeight();
- }
- }
-
class StackScrollAlgorithmState {
/**