Fully removed the bottom stack

Moved the ambient notifications into the shelf
instead of having them behave with their own
physics. Previously the ambient notifications
were stuck in the old world behind the shelf,
but this doesn't make sense anymore.

This also fixed a bug where the notifications were
wrongly positioned on the lockscreen since the shelf
counted as a view that wasn't gone.

Test: add low-priority notifications, observe scrolling
Bug: 32437839
Change-Id: I3921ea9f80a06f1b6330315423b012174269ac8e
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 11d42b3..ded85eb 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -273,16 +273,10 @@
     <!-- Default distance from each snap target that GlowPadView considers a "hit" -->
     <dimen name="glowpadview_inner_radius">15dip</dimen>
 
-    <!-- Space reserved for the cards behind the top card in the bottom stack -->
-    <dimen name="bottom_stack_peek_amount">12dp</dimen>
-
     <!-- bottom_stack_peek_amount + notification_min_height
          + notification_collapse_second_card_padding -->
     <dimen name="min_stack_height">104dp</dimen>
 
-    <!-- The height of the area before the bottom stack in which the notifications slow down -->
-    <dimen name="bottom_stack_slow_down_length">12dp</dimen>
-
     <!-- Z distance between notifications if they are in the stack -->
     <dimen name="z_distance_between_notifications">0.5dp</dimen>
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index 7ca4ad6..f629c04 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -37,7 +37,6 @@
 import com.android.systemui.classifier.FalsingManager;
 import com.android.systemui.statusbar.notification.FakeShadowView;
 import com.android.systemui.statusbar.notification.NotificationUtils;
-import com.android.systemui.statusbar.stack.ExpandableViewState;
 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
 import com.android.systemui.statusbar.stack.StackStateAnimator;
 
@@ -132,7 +131,7 @@
     private final int mLegacyColor;
     private final int mNormalColor;
     private final int mLowPriorityColor;
-    private boolean mIsBelowShelf;
+    private boolean mIsBelowSpeedBump;
     private FalsingManager mFalsingManager;
     private boolean mTrackTouch;
 
@@ -444,14 +443,25 @@
     }
 
     @Override
-    public void setBelowShelf(boolean below) {
-        super.setBelowShelf(below);
-        if (below != mIsBelowShelf) {
-            mIsBelowShelf = below;
+    public void setBelowSpeedBump(boolean below) {
+        super.setBelowSpeedBump(below);
+        if (below != mIsBelowSpeedBump) {
+            mIsBelowSpeedBump = below;
             updateBackgroundTint();
+            onBelowSpeedBumpChanged();
         }
     }
 
+    protected void onBelowSpeedBumpChanged() {
+    }
+
+    /**
+     * @return whether we are below the speed bump
+     */
+    public boolean isBelowSpeedBump() {
+        return mIsBelowSpeedBump;
+    }
+
     /**
      * Sets the tint color of the background
      */
@@ -857,7 +867,7 @@
             return mBgTint;
         } else if (mShowingLegacyBackground) {
             return mLegacyColor;
-        } else if (mIsBelowShelf) {
+        } else if (mIsBelowSpeedBump) {
             return mLowPriorityColor;
         } else {
             return mNormalColor;
@@ -869,7 +879,7 @@
             return mTintedRippleColor;
         } else if (mShowingLegacyBackground) {
             return mTintedRippleColor;
-        } else if (mIsBelowShelf) {
+        } else if (mIsBelowSpeedBump) {
             return mLowPriorityRippleColor;
         } else {
             return mNormalRippleColor;
@@ -915,7 +925,7 @@
         setTintColor(0);
         resetBackgroundAlpha();
         setShowingLegacyBackground(false);
-        setBelowShelf(false);
+        setBelowSpeedBump(false);
     }
 
     public boolean hasSameBgColor(ActivatableNotificationView otherView) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index a19978a..86de774 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -413,6 +413,7 @@
         if (mNotificationParent != null) {
             mNotificationParent.updateBackgroundForGroupState();
         }
+        updateIconVisibilities();
     }
 
     @Override
@@ -847,6 +848,11 @@
         }
     }
 
+    @Override
+    protected void onBelowSpeedBumpChanged() {
+        updateIconVisibilities();
+    }
+
     private void updateContentFadeOut() {
         if (!isChildInGroup()) {
             float contentAlpha = 1.0f - mIconTransformationAmount;
@@ -866,12 +872,11 @@
     }
 
     private void updateIconVisibilities() {
-        if (!isChildInGroup()) {
-            mPublicLayout.setIconsVisible(mIconsVisible);
-            mPrivateLayout.setIconsVisible(mIconsVisible);
-            if (mChildrenContainer != null) {
-                mChildrenContainer.setIconsVisible(mIconsVisible);
-            }
+        boolean visible = isChildInGroup() || isBelowSpeedBump() || mIconsVisible;
+        mPublicLayout.setIconsVisible(visible);
+        mPrivateLayout.setIconsVisible(visible);
+        if (mChildrenContainer != null) {
+            mChildrenContainer.setIconsVisible(visible);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
index 0db0896d..0f5981b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
@@ -283,10 +283,10 @@
     public abstract void performAddAnimation(long delay, long duration);
 
     /**
-     * Set the notification appearance to be below the shelf.
+     * Set the notification appearance to be below the speed bump.
      * @param below true if it is below.
      */
-    public void setBelowShelf(boolean below) {
+    public void setBelowSpeedBump(boolean below) {
     }
 
     public int getPinnedHeadsUpHeight() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index ada24f3..8d68eda 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -32,7 +32,6 @@
 import com.android.systemui.statusbar.stack.AnimationProperties;
 import com.android.systemui.statusbar.stack.ExpandableViewState;
 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
-import com.android.systemui.statusbar.stack.StackScrollAlgorithm;
 import com.android.systemui.statusbar.stack.StackScrollState;
 
 import java.util.ArrayList;
@@ -131,13 +130,11 @@
     }
 
     public void updateState(StackScrollState resultState,
-            StackScrollAlgorithm.StackScrollAlgorithmState algorithmState,
             AmbientState ambientState) {
-        int shelfIndex = ambientState.getShelfIndex() - 1;
-        if (shelfIndex != -1) {
+        View lastView = ambientState.getLastVisibleBackgroundChild();
+        if (lastView != null) {
             float maxShelfEnd = ambientState.getInnerHeight() + ambientState.getTopPadding()
                     + ambientState.getStackTranslation();
-            ExpandableView lastView = algorithmState.visibleChildren.get(shelfIndex);
             ExpandableViewState lastViewState = resultState.getViewStateForView(lastView);
             float viewEnd = lastViewState.yTranslation + lastViewState.height;
             mShelfState.copyFrom(lastViewState);
@@ -151,7 +148,7 @@
             mShelfState.openedAmount = openedAmount;
             mShelfState.clipTopAmount = 0;
             mShelfState.alpha = 1.0f;
-            mShelfState.belowShelf = false;
+            mShelfState.belowSpeedBump = false;
             mShelfState.shadowAlpha = 1.0f;
             mShelfState.isBottomClipped = false;
             mShelfState.hideSensitive = false;
@@ -174,8 +171,8 @@
     public void updateAppearance() {
         WeakHashMap<View, NotificationIconContainer.IconState> iconStates =
                 mShelfIcons.resetViewStates();
-        float numIconsInShelf = 0.0f;
-        int shelfIndex = mAmbientState.getShelfIndex();
+        float numViewsInShelf = 0.0f;
+        View lastChild = mAmbientState.getLastVisibleBackgroundChild();
         mNotGoneIndex = -1;
         float interpolationStart = mMaxLayoutHeight - getIntrinsicHeight() * 2;
         float expandAmount = 0.0f;
@@ -185,8 +182,12 @@
         }
         //  find the first view that doesn't overlap with the shelf
         int notificationIndex = 0;
-        int notGoneNotifications = 0;
-        while (notGoneNotifications < shelfIndex) {
+        int notGoneIndex = 0;
+        boolean backgroundForceHidden = false;
+        if (mHideBackground && !mShelfState.hasItemsInStableShelf) {
+            backgroundForceHidden = true;
+        }
+        while (notificationIndex < mHostLayout.getChildCount()) {
             ExpandableView child = (ExpandableView) mHostLayout.getChildAt(notificationIndex);
             notificationIndex++;
             if (!(child instanceof ExpandableNotificationRow)
@@ -199,7 +200,7 @@
             float notificationClipEnd;
             float shelfStart = getTranslationY();
             boolean aboveShelf = row.getTranslationZ() > mAmbientState.getBaseZHeight();
-            if (notGoneNotifications == shelfIndex - 1 || aboveShelf) {
+            if (child == lastChild || aboveShelf || backgroundForceHidden) {
                 notificationClipEnd = shelfStart + getIntrinsicHeight();
             } else {
                 notificationClipEnd = shelfStart - mPaddingBetweenElements;
@@ -212,34 +213,25 @@
                 }
             }
             updateNotificationClipHeight(row, notificationClipEnd);
-            updateIconAppearance(row, iconState, icon, expandAmount);
-            numIconsInShelf += iconState.iconAppearAmount;
+            numViewsInShelf += updateIconAppearance(row, iconState, icon, expandAmount);
             if (row.getTranslationY() >= getTranslationY() && mNotGoneIndex == -1) {
-                mNotGoneIndex = notGoneNotifications;
+                mNotGoneIndex = notGoneIndex;
             }
-            if (notGoneNotifications != 0 || !aboveShelf) {
+            if (notGoneIndex != 0 || !aboveShelf) {
                 row.setAboveShelf(false);
             }
-            notGoneNotifications++;
-        }
-        while (notificationIndex < mHostLayout.getChildCount()) {
-            // We need to reset the clipping in case a notification switches from high to low
-            // priority.
-            ExpandableView child = (ExpandableView) mHostLayout.getChildAt(notificationIndex);
-            if (child.getClipBottomAmount() != 0) {
-                child.setClipBottomAmount(0);
-            }
-            if (child instanceof ExpandableNotificationRow) {
-                ExpandableNotificationRow row = (ExpandableNotificationRow) child;
-                row.setIconTransformationAmount(0);
-            }
-            notificationIndex++;
+            notGoneIndex++;
         }
         mShelfIcons.calculateIconTranslations();
         mShelfIcons.applyIconStates();
-        setVisibility(numIconsInShelf == 0.0f || !mAmbientState.isShadeExpanded() ? INVISIBLE
-                : VISIBLE);
-        setHideBackground(numIconsInShelf < 1.0f);
+        setVisibility(numViewsInShelf != 0.0f && mAmbientState.isShadeExpanded()
+                ? VISIBLE
+                : INVISIBLE);
+        boolean hideBackground = numViewsInShelf < 1.0f;
+        setHideBackground(hideBackground || backgroundForceHidden);
+        if (mNotGoneIndex == -1) {
+            mNotGoneIndex = notGoneIndex;
+        }
     }
 
     private void updateNotificationClipHeight(ExpandableNotificationRow row,
@@ -254,13 +246,16 @@
         }
     }
 
-    private void updateIconAppearance(ExpandableNotificationRow row,
+    private float updateIconAppearance(ExpandableNotificationRow row,
             NotificationIconContainer.IconState iconState, StatusBarIconView icon,
             float expandAmount) {
         // Let calculate how much the view is in the shelf
         float viewStart = row.getTranslationY();
         int transformHeight = row.getActualHeight() + mPaddingBetweenElements;
         float viewEnd = viewStart + transformHeight;
+        float iconAppearAmount;
+        float yTranslation;
+        float alpha = 1.0f;
         if (viewEnd >= getTranslationY() && (mAmbientState.isShadeExpanded()
                 || (!row.isPinned() && !row.isHeadsUpAnimatingAway()))) {
             if (viewStart < getTranslationY()) {
@@ -269,12 +264,12 @@
                         linearAmount);
                 interpolatedAmount = NotificationUtils.interpolate(
                         interpolatedAmount, linearAmount, expandAmount);
-                iconState.iconAppearAmount = 1.0f - interpolatedAmount;
+                iconAppearAmount = 1.0f - interpolatedAmount;
             } else {
-                iconState.iconAppearAmount = 1.0f;
+                iconAppearAmount = 1.0f;
             }
         } else {
-            iconState.iconAppearAmount = 0.0f;
+            iconAppearAmount = 0.0f;
         }
 
         // Lets now calculate how much of the transformation has already happened. This is different
@@ -300,12 +295,12 @@
                 || (!mAmbientState.isShadeExpanded()
                         && (row.isPinned() || row.isHeadsUpAnimatingAway()))) {
             // We simply place it on the icon of the notification
-            iconState.yTranslation = notificationIconPosition - shelfIconPosition;
+            yTranslation = notificationIconPosition - shelfIconPosition;
         } else {
             transitionAmount = (viewStart - transformationStartPosition)
                     / transitionDistance;
             float startPosition = transformationStartPosition + iconTopPadding;
-            iconState.yTranslation = NotificationUtils.interpolate(
+            yTranslation = NotificationUtils.interpolate(
                     startPosition - shelfIconPosition, 0, transitionAmount);
             // If we are merging into the shelf, lets make sure the shelf is at least on our height,
             // otherwise the icons won't be visible.
@@ -314,24 +309,30 @@
         float shelfIconSize = icon.getHeight() * icon.getIconScale();
         if (!row.isShowingIcon()) {
             // The view currently doesn't have an icon, lets transform it in!
-            iconState.alpha = transitionAmount;
+            alpha = transitionAmount;
             notificationIconSize = shelfIconSize / 2.0f;
         }
         // The notification size is different from the size in the shelf / statusbar
         float newSize = NotificationUtils.interpolate(notificationIconSize, shelfIconSize,
                 transitionAmount);
-        iconState.scaleX = newSize / icon.getHeight() / icon.getIconScale();
-        iconState.scaleY = iconState.scaleX;
-        iconState.hidden = transitionAmount == 0.0f;
         row.setIconTransformationAmount(transitionAmount);
-        icon.setVisibility(transitionAmount == 0.0f ? INVISIBLE : VISIBLE);
-        if (row.isInShelf() && !row.isTransformingIntoShelf()) {
-            iconState.iconAppearAmount = 1.0f;
-            iconState.alpha = 1.0f;
-            iconState.scaleX = 1.0f;
-            iconState.scaleY = 1.0f;
-            iconState.hidden = false;
+        if (iconState != null) {
+            iconState.scaleX = newSize / icon.getHeight() / icon.getIconScale();
+            iconState.scaleY = iconState.scaleX;
+            iconState.hidden = transitionAmount == 0.0f;
+            iconState.iconAppearAmount = iconAppearAmount;
+            iconState.alpha = alpha;
+            iconState.yTranslation = yTranslation;
+            icon.setVisibility(transitionAmount == 0.0f ? INVISIBLE : VISIBLE);
+            if (row.isInShelf() && !row.isTransformingIntoShelf()) {
+                iconState.iconAppearAmount = 1.0f;
+                iconState.alpha = 1.0f;
+                iconState.scaleX = 1.0f;
+                iconState.scaleY = 1.0f;
+                iconState.hidden = false;
+            }
         }
+        return iconAppearAmount;
     }
 
     private float getFullyClosedTranslation() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index f2ea991..523528d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -1490,9 +1490,7 @@
         // and expanding/collapsing the whole panel from/to quick settings.
         if (mNotificationStackScroller.getNotGoneChildCount() == 0
                 && mShadeEmpty) {
-            notificationHeight = mNotificationStackScroller.getEmptyShadeViewHeight()
-                    + mNotificationStackScroller.getBottomStackPeekSize()
-                    + mNotificationStackScroller.getBottomStackSlowDownHeight();
+            notificationHeight = mNotificationStackScroller.getEmptyShadeViewHeight();
         }
         int maxQsHeight = mQsMaxExpansionHeight;
 
@@ -1523,8 +1521,7 @@
 
     private float getFadeoutAlpha() {
         float alpha = (getNotificationsTopY() + mNotificationStackScroller.getFirstItemMinHeight())
-                / (mQsMinExpansionHeight + mNotificationStackScroller.getBottomStackPeekSize()
-                - mNotificationStackScroller.getBottomStackSlowDownHeight());
+                / mQsMinExpansionHeight;
         alpha = Math.max(0, Math.min(alpha, 1));
         alpha = (float) Math.pow(alpha, 0.75);
         return alpha;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 604e8e1..bb86d6f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -1868,7 +1868,7 @@
         mTmpChildOrderMap.clear();
 
         updateRowStates();
-        updateShelfIndex();
+        updateSpeedBumpIndex();
         updateClearAll();
         updateEmptyShadeView();
 
@@ -1989,8 +1989,8 @@
         mNotificationPanel.setShadeEmpty(showEmptyShade);
     }
 
-    private void updateShelfIndex() {
-        int shelfIndex = -1;
+    private void updateSpeedBumpIndex() {
+        int speedBumpIndex = -1;
         int currentIndex = 0;
         final int N = mStackScroller.getChildCount();
         for (int i = 0; i < N; i++) {
@@ -2000,17 +2000,17 @@
             }
             ExpandableNotificationRow row = (ExpandableNotificationRow) view;
             if (mNotificationData.isAmbient(row.getStatusBarNotification().getKey())) {
-                shelfIndex = currentIndex;
+                speedBumpIndex = currentIndex;
                 break;
             }
             currentIndex++;
         }
         boolean noAmbient = false;
-        if (shelfIndex == -1) {
-            shelfIndex = currentIndex;
+        if (speedBumpIndex == -1) {
+            speedBumpIndex = currentIndex;
             noAmbient = true;
         }
-        mStackScroller.updateShelfIndex(shelfIndex, noAmbient);
+        mStackScroller.updateSpeedBumpIndex(speedBumpIndex, noAmbient);
     }
 
     public static boolean isTopLevelChild(Entry entry) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
index 6f9e2e5..26f74ea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
@@ -36,7 +36,7 @@
     private ActivatableNotificationView mActivatedChild;
     private float mOverScrollTopAmount;
     private float mOverScrollBottomAmount;
-    private int mShelfIndex = -1;
+    private int mSpeedBumpIndex = -1;
     private boolean mDark;
     private boolean mHideSensitive;
     private HeadsUpManager mHeadsUpManager;
@@ -51,6 +51,7 @@
     private int mZDistanceBetweenElements;
     private int mBaseZHeight;
     private int mMaxLayoutHeight;
+    private ActivatableNotificationView mLastVisibleBackgroundChild;
 
     public AmbientState(Context context) {
         reload(context);
@@ -62,8 +63,7 @@
     public void reload(Context context) {
         mZDistanceBetweenElements = Math.max(1, context.getResources()
                 .getDimensionPixelSize(R.dimen.z_distance_between_notifications));
-        mBaseZHeight = (StackScrollAlgorithm.MAX_ITEMS_IN_BOTTOM_STACK + 1)
-                * mZDistanceBetweenElements;
+        mBaseZHeight = 4 * mZDistanceBetweenElements;
     }
 
     /**
@@ -153,12 +153,12 @@
         return top ? mOverScrollTopAmount : mOverScrollBottomAmount;
     }
 
-    public int getShelfIndex() {
-        return mShelfIndex;
+    public int getSpeedBumpIndex() {
+        return mSpeedBumpIndex;
     }
 
-    public void setShelfIndex(int shelfIndex) {
-        mShelfIndex = shelfIndex;
+    public void setSpeedBumpIndex(int shelfIndex) {
+        mSpeedBumpIndex = shelfIndex;
     }
 
     public void setHeadsUpManager(HeadsUpManager headsUpManager) {
@@ -228,4 +228,17 @@
     public void setLayoutMaxHeight(int maxLayoutHeight) {
         mMaxLayoutHeight = maxLayoutHeight;
     }
+
+    /**
+     * Sets the last visible view of the host layout, that has a background, i.e the very last
+     * view in the shade, without the clear all button.
+     */
+    public void setLastVisibleBackgroundChild(
+            ActivatableNotificationView lastVisibleBackgroundChild) {
+        mLastVisibleBackgroundChild = lastVisibleBackgroundChild;
+    }
+
+    public ActivatableNotificationView getLastVisibleBackgroundChild() {
+        return mLastVisibleBackgroundChild;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/ExpandableViewState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/ExpandableViewState.java
index bcd278d7..58e6838 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/ExpandableViewState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/ExpandableViewState.java
@@ -84,7 +84,7 @@
     public boolean dimmed;
     public boolean dark;
     public boolean hideSensitive;
-    public boolean belowShelf;
+    public boolean belowSpeedBump;
     public float shadowAlpha;
     public boolean inShelf;
 
@@ -121,7 +121,7 @@
             shadowAlpha = svs.shadowAlpha;
             dark = svs.dark;
             hideSensitive = svs.hideSensitive;
-            belowShelf = svs.belowShelf;
+            belowSpeedBump = svs.belowSpeedBump;
             clipTopAmount = svs.clipTopAmount;
             notGoneIndex = svs.notGoneIndex;
             location = svs.location;
@@ -161,8 +161,8 @@
             expandableView.setHideSensitive(
                     this.hideSensitive, false /* animated */, 0 /* delay */, 0 /* duration */);
 
-            // apply below shelf speedBump
-            expandableView.setBelowShelf(this.belowShelf);
+            // apply below shelf speed bump
+            expandableView.setBelowSpeedBump(this.belowSpeedBump);
 
             // apply dark
             expandableView.setDark(this.dark, false /* animate */, 0 /* delay */);
@@ -211,8 +211,8 @@
         // start dimmed animation
         expandableView.setDimmed(this.dimmed, animationFilter.animateDimmed);
 
-        // apply below shelf state
-        expandableView.setBelowShelf(this.belowShelf);
+        // apply below the speed bump
+        expandableView.setBelowSpeedBump(this.belowSpeedBump);
 
         // start hiding sensitive animation
         expandableView.setHideSensitive(this.hideSensitive, animationFilter.animateHideSensitive,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
index 33b9d38..8c8e088 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
@@ -479,7 +479,7 @@
             childState.dimmed = parentState.dimmed;
             childState.dark = parentState.dark;
             childState.hideSensitive = parentState.hideSensitive;
-            childState.belowShelf = parentState.belowShelf;
+            childState.belowSpeedBump = parentState.belowSpeedBump;
             childState.clipTopAmount = 0;
             childState.alpha = 0;
             if (i < firstOverflowIndex) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 20ca510..49da793 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -135,8 +135,6 @@
     private Paint mDebugPaint;
     private int mContentHeight;
     private int mCollapsedSize;
-    private int mBottomStackSlowDownHeight;
-    private int mBottomStackPeekSize;
     private int mPaddingBetweenElements;
     private int mIncreasedPaddingBetweenElements;
     private int mTopPadding;
@@ -424,11 +422,6 @@
         if (DEBUG) {
             int y = mTopPadding;
             canvas.drawLine(0, y, getWidth(), y, mDebugPaint);
-            y = (int) (getLayoutHeight() - mBottomStackPeekSize
-                    - mBottomStackSlowDownHeight);
-            canvas.drawLine(0, y, getWidth(), y, mDebugPaint);
-            y = (int) (getLayoutHeight() - mBottomStackPeekSize);
-            canvas.drawLine(0, y, getWidth(), y, mDebugPaint);
             y = (int) getLayoutHeight();
             canvas.drawLine(0, y, getWidth(), y, mDebugPaint);
             y = getHeight() - getEmptyBottomMargin();
@@ -465,15 +458,12 @@
         mOverflingDistance = configuration.getScaledOverflingDistance();
         mCollapsedSize = context.getResources()
                 .getDimensionPixelSize(R.dimen.notification_min_height);
-        mBottomStackPeekSize = context.getResources()
-                .getDimensionPixelSize(R.dimen.bottom_stack_peek_amount);
         mStackScrollAlgorithm.initView(context);
         mAmbientState.reload(context);
         mPaddingBetweenElements = Math.max(1, context.getResources()
                 .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);
         mStatusBarHeight = getResources().getDimensionPixelOffset(R.dimen.status_bar_height);
@@ -537,8 +527,8 @@
         }
     }
 
-    public void updateShelfIndex(int newIndex, boolean noAmbient) {
-        mAmbientState.setShelfIndex(newIndex);
+    public void updateSpeedBumpIndex(int newIndex, boolean noAmbient) {
+        mAmbientState.setSpeedBumpIndex(newIndex);
         mNoAmbient = noAmbient;
     }
 
@@ -777,13 +767,12 @@
     private float getAppearEndPosition() {
         int appearPosition;
         if (mTrackingHeadsUp || mHeadsUpManager.hasPinnedHeadsUp()) {
-            appearPosition = mHeadsUpManager.getTopHeadsUpPinnedHeight() + mBottomStackPeekSize
-                    + mBottomStackSlowDownHeight;
+            appearPosition = mHeadsUpManager.getTopHeadsUpPinnedHeight();
         } else {
             appearPosition = getFirstItemMinHeight();
-            if (mAmbientState.getShelfIndex() > 1) {
-                appearPosition += mShelf.getIntrinsicHeight();
-            }
+        }
+        if (getNotGoneChildCount() > 1) {
+            appearPosition += mShelf.getIntrinsicHeight();
         }
         return appearPosition + (onKeyguard() ? mTopPadding : mIntrinsicPadding);
     }
@@ -826,14 +815,6 @@
         return firstChild != null ? firstChild.getMinHeight() : mCollapsedSize;
     }
 
-    public int getBottomStackPeekSize() {
-        return mBottomStackPeekSize;
-    }
-
-    public int getBottomStackSlowDownHeight() {
-        return mBottomStackSlowDownHeight;
-    }
-
     public void setLongPressListener(SwipeHelper.LongPressListener listener) {
         mSwipeHelper.setLongPressListener(listener);
         mLongPressListener = listener;
@@ -1803,8 +1784,7 @@
 
     private int getScrollRange() {
         int contentHeight = getContentHeight();
-        int scrollRange = Math.max(0, contentHeight - mMaxLayoutHeight + mBottomStackPeekSize
-                + mBottomStackSlowDownHeight);
+        int scrollRange = Math.max(0, contentHeight - mMaxLayoutHeight);
         int imeInset = getImeInset();
         scrollRange += Math.min(imeInset, Math.max(0,
                 getContentHeight() - (getHeight() - imeInset)));
@@ -1822,7 +1802,7 @@
         int childCount = getChildCount();
         for (int i = 0; i < childCount; i++) {
             View child = getChildAt(i);
-            if (child.getVisibility() != View.GONE) {
+            if (child.getVisibility() != View.GONE && child != mShelf) {
                 return (ExpandableView) child;
             }
         }
@@ -1869,7 +1849,7 @@
         int childCount = getChildCount();
         for (int i = childCount - 1; i >= 0; i--) {
             View child = getChildAt(i);
-            if (child.getVisibility() != View.GONE) {
+            if (child.getVisibility() != View.GONE && child != mShelf) {
                 return child;
             }
         }
@@ -1884,7 +1864,7 @@
         int count = 0;
         for (int i = 0; i < childCount; i++) {
             ExpandableView child = (ExpandableView) getChildAt(i);
-            if (child.getVisibility() != View.GONE && !child.willBeGone()) {
+            if (child.getVisibility() != View.GONE && !child.willBeGone() && child != mShelf) {
                 count++;
             }
         }
@@ -2311,8 +2291,11 @@
         final ExpandableView firstChild = getFirstChildNotGone();
         final int firstChildMinHeight = firstChild != null ? firstChild.getCollapsedHeight()
                 : mCollapsedSize;
-        return mIntrinsicPadding + firstChildMinHeight + mBottomStackPeekSize
-                + mBottomStackSlowDownHeight;
+        int shelfHeight = 0;
+        if (mLastVisibleBackgroundChild != null) {
+            shelfHeight = mShelf.getIntrinsicHeight();
+        }
+        return mIntrinsicPadding + firstChildMinHeight + shelfHeight;
     }
 
     private int clampPadding(int desiredPadding) {
@@ -2651,6 +2634,7 @@
         }
         mFirstVisibleBackgroundChild = firstChild;
         mLastVisibleBackgroundChild = lastChild;
+        mAmbientState.setLastVisibleBackgroundChild(lastChild);
     }
 
     private void onViewAddedInternal(View child) {
@@ -3152,13 +3136,7 @@
     }
 
     public int getEmptyBottomMargin() {
-        int emptyMargin = mMaxLayoutHeight - mContentHeight;
-        if (!mNoAmbient || mEmptyShadeView.getVisibility() == VISIBLE) {
-            // If we have ambient notifications or a clear all button, we need to make sure that the
-            // notifications are a bit taller, otherwise they will be pushed under the other cards
-            emptyMargin -= (mBottomStackPeekSize + mBottomStackSlowDownHeight);
-        }
-        return Math.max(emptyMargin, 0);
+        return Math.max(mMaxLayoutHeight - mContentHeight, 0);
     }
 
     public void onExpansionStarted() {
@@ -3268,20 +3246,18 @@
                 if (row.isChildInGroup()) {
                     endPosition += row.getNotificationParent().getTranslationY();
                 }
-                int stackEnd = getStackEndPosition();
-                if (endPosition > stackEnd) {
-                    setOwnScrollY((int) (mOwnScrollY + endPosition - stackEnd));
+                int layoutEnd = mMaxLayoutHeight + (int) mStackTranslation;
+                if (row != mLastVisibleBackgroundChild) {
+                    layoutEnd -= mShelf.getIntrinsicHeight() + mPaddingBetweenElements;
+                }
+                if (endPosition > layoutEnd) {
+                    setOwnScrollY((int) (mOwnScrollY + endPosition - layoutEnd));
                     mDisallowScrollingInThisMotion = true;
                 }
             }
         }
     }
 
-    private int getStackEndPosition() {
-        return mMaxLayoutHeight - mBottomStackPeekSize - mBottomStackSlowDownHeight
-                + mPaddingBetweenElements + (int) mStackTranslation;
-    }
-
     public void setOnHeightChangedListener(
             ExpandableView.OnHeightChangedListener mOnHeightChangedListener) {
         this.mOnHeightChangedListener = mOnHeightChangedListener;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/PiecewiseLinearIndentationFunctor.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/PiecewiseLinearIndentationFunctor.java
deleted file mode 100644
index 1c37c35..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/PiecewiseLinearIndentationFunctor.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.statusbar.stack;
-
-import java.util.ArrayList;
-
-/**
- * A Functor which interpolates the stack distance linearly based on base values.
- * The base values are based on an interpolation between a linear function and a
- * quadratic function
- */
-public class PiecewiseLinearIndentationFunctor extends StackIndentationFunctor {
-
-    private final ArrayList<Float> mBaseValues;
-    private final float mLinearPart;
-
-    /**
-     * @param maxItemsInStack The maximum number of items which should be visible at the same time,
-     *                        i.e the function returns totalTransitionDistance for the element with
-     *                        index maxItemsInStack
-     * @param peekSize The visual appearance of this is how far the cards in the stack peek
-     *                 out below the top card and it is measured in real pixels.
-     *                 Note that the visual appearance does not necessarily always correspond to
-     *                 the actual visual distance below the top card but is a maximum,
-     *                 achieved when the next card just starts transitioning into the stack and
-     *                 the stack is full.
-     *                 If distanceToPeekStart is 0, we directly start at the peek, otherwise the
-     *                 first element transitions between 0 and distanceToPeekStart.
-     *                 Visualization:
-     *           ---------------------------------------------------   ---
-     *          |                                                   |   |
-     *          |                  FIRST ITEM                       |   | <- distanceToPeekStart
-     *          |                                                   |   |
-     *          |---------------------------------------------------|  ---  ---
-     *          |__________________SECOND ITEM______________________|        |  <- peekSize
-     *          |===================================================|       _|_
-     *
-     * @param distanceToPeekStart The distance to the start of the peak.
-     * @param linearPart The interpolation factor between the linear and the quadratic amount taken.
-     *                   This factor must be somewhere in [0 , 1]
-     */
-    PiecewiseLinearIndentationFunctor(int maxItemsInStack,
-                                      int peekSize,
-                                      int distanceToPeekStart,
-                                      float linearPart) {
-        super(maxItemsInStack, peekSize, distanceToPeekStart);
-        mBaseValues = new ArrayList<Float>(maxItemsInStack+1);
-        initBaseValues();
-        mLinearPart = linearPart;
-    }
-
-    private void initBaseValues() {
-        int sumOfSquares = getSumOfSquares(mMaxItemsInStack-1);
-        int totalWeight = 0;
-        mBaseValues.add(0.0f);
-        for (int i = 0; i < mMaxItemsInStack - 1; i++) {
-            totalWeight += (mMaxItemsInStack - i - 1) * (mMaxItemsInStack - i - 1);
-            mBaseValues.add((float) totalWeight / sumOfSquares);
-        }
-    }
-
-    /**
-     * Get the sum of squares up to and including n, i.e sum(i * i, 1, n)
-     *
-     * @param n the maximum square to include
-     * @return
-     */
-    private int getSumOfSquares(int n) {
-        return n * (n + 1) * (2 * n + 1) / 6;
-    }
-
-    @Override
-    public float getValue(float itemsBefore) {
-        if (mStackStartsAtPeek) {
-            // We directly start at the stack, so no initial interpolation.
-            itemsBefore++;
-        }
-        if (itemsBefore < 0) {
-            return 0;
-        } else if (itemsBefore >= mMaxItemsInStack) {
-            return mTotalTransitionDistance;
-        }
-        int below = (int) itemsBefore;
-        float partialIn = itemsBefore - below;
-
-        if (below == 0) {
-            return mDistanceToPeekStart * partialIn;
-        } else {
-            float result = mDistanceToPeekStart;
-            float progress = mBaseValues.get(below - 1) * (1 - partialIn)
-                    + mBaseValues.get(below) * partialIn;
-            result += (progress * (1 - mLinearPart)
-                    + (itemsBefore - 1) / (mMaxItemsInStack - 1)  * mLinearPart) * mPeekSize;
-            return result;
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackIndentationFunctor.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackIndentationFunctor.java
deleted file mode 100644
index 034eba6..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackIndentationFunctor.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.statusbar.stack;
-
-/**
- * A functor which can be queried for offset given the number of items before it.
- */
-public abstract class StackIndentationFunctor {
-
-    protected int mTotalTransitionDistance;
-    protected int mDistanceToPeekStart;
-    protected int mMaxItemsInStack;
-    protected int mPeekSize;
-    protected boolean mStackStartsAtPeek;
-
-    /**
-     * @param maxItemsInStack The maximum number of items which should be visible at the same time,
-     *                        i.e the function returns totalTransitionDistance for the element with
-     *                        index maxItemsInStack
-     * @param peekSize The visual appearance of this is how far the cards in the stack peek
-     *                 out below the top card and it is measured in real pixels.
-     *                 Note that the visual appearance does not necessarily always correspond to
-     *                 the actual visual distance below the top card but is a maximum,
-     *                 achieved when the next card just starts transitioning into the stack and
-     *                 the stack is full.
-     *                 If distanceToPeekStart is 0, we directly start at the peek, otherwise the
-     *                 first element transitions between 0 and distanceToPeekStart.
-     *                 Visualization:
-     *           ---------------------------------------------------   ---
-     *          |                                                   |   |
-     *          |                  FIRST ITEM                       |   | <- distanceToPeekStart
-     *          |                                                   |   |
-     *          |---------------------------------------------------|  ---  ---
-     *          |__________________SECOND ITEM______________________|        |  <- peekSize
-     *          |===================================================|       _|_
-     *
-     * @param distanceToPeekStart The distance to the start of the peak.
-     */
-    StackIndentationFunctor(int maxItemsInStack, int peekSize, int distanceToPeekStart) {
-        mDistanceToPeekStart = distanceToPeekStart;
-        mStackStartsAtPeek = mDistanceToPeekStart == 0;
-        mMaxItemsInStack = maxItemsInStack;
-        mPeekSize = peekSize;
-        updateTotalTransitionDistance();
-
-    }
-
-    private void updateTotalTransitionDistance() {
-        mTotalTransitionDistance = mDistanceToPeekStart + mPeekSize;
-    }
-
-    public void setPeekSize(int mPeekSize) {
-        this.mPeekSize = mPeekSize;
-        updateTotalTransitionDistance();
-    }
-
-    public void setDistanceToPeekStart(int distanceToPeekStart) {
-        mDistanceToPeekStart = distanceToPeekStart;
-        mStackStartsAtPeek = mDistanceToPeekStart == 0;
-        updateTotalTransitionDistance();
-    }
-
-    /**
-     * Gets the offset of this Functor given a the quantity of items before it
-     *
-     * @param itemsBefore how many items are already in the stack before this element
-     * @return the offset
-     */
-    public abstract float getValue(float itemsBefore);
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
index 29be66a..1dc346d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -26,7 +26,6 @@
 import com.android.systemui.statusbar.ExpandableNotificationRow;
 import com.android.systemui.statusbar.ExpandableView;
 import com.android.systemui.statusbar.NotificationShelf;
-import com.android.systemui.statusbar.notification.FakeShadowView;
 import com.android.systemui.statusbar.notification.NotificationUtils;
 
 import java.util.ArrayList;
@@ -42,18 +41,12 @@
 
     private static final String LOG_TAG = "StackScrollAlgorithm";
 
-    public static final int MAX_ITEMS_IN_BOTTOM_STACK = 3;
-
     private int mPaddingBetweenElements;
     private int mIncreasedPaddingBetweenElements;
     private int mCollapsedSize;
-    private int mBottomStackPeekSize;
-
-    private StackIndentationFunctor mBottomStackIndentationFunctor;
 
     private StackScrollAlgorithmState mTempAlgorithmState = new StackScrollAlgorithmState();
     private boolean mIsExpanded;
-    private int mBottomStackSlowDownLength;
     private int mStatusBarHeight;
 
     public StackScrollAlgorithm(Context context) {
@@ -64,26 +57,13 @@
         initConstants(context);
     }
 
-    public int getBottomStackSlowDownLength() {
-        return mBottomStackSlowDownLength + mPaddingBetweenElements;
-    }
-
     private void initConstants(Context context) {
-        mPaddingBetweenElements = Math.max(1, context.getResources()
-                .getDimensionPixelSize(R.dimen.notification_divider_height));
+        mPaddingBetweenElements = context.getResources().getDimensionPixelSize(
+                R.dimen.notification_divider_height);
         mIncreasedPaddingBetweenElements = context.getResources()
                 .getDimensionPixelSize(R.dimen.notification_divider_height_increased);
         mCollapsedSize = context.getResources()
                 .getDimensionPixelSize(R.dimen.notification_min_height);
-        mBottomStackPeekSize = context.getResources()
-                .getDimensionPixelSize(R.dimen.bottom_stack_peek_amount);
-        mBottomStackSlowDownLength = context.getResources()
-                .getDimensionPixelSize(R.dimen.bottom_stack_slow_down_length);
-        mBottomStackIndentationFunctor = new PiecewiseLinearIndentationFunctor(
-                MAX_ITEMS_IN_BOTTOM_STACK,
-                mBottomStackPeekSize,
-                getBottomStackSlowDownLength(),
-                0.5f);
         mStatusBarHeight = context.getResources().getDimensionPixelSize(R.dimen.status_bar_height);
     }
 
@@ -106,7 +86,8 @@
         handleDraggedViews(ambientState, resultState, algorithmState);
         updateDimmedActivatedHideSensitive(ambientState, resultState, algorithmState);
         updateClipping(resultState, algorithmState, ambientState);
-        updateShelfState(resultState, algorithmState, ambientState);
+        updateSpeedBumpState(resultState, algorithmState, ambientState);
+        updateShelfState(resultState, ambientState);
         getNotificationChildrenStates(resultState, algorithmState);
     }
 
@@ -122,20 +103,23 @@
         }
     }
 
-    private void updateShelfState(StackScrollState resultState,
+    private void updateSpeedBumpState(StackScrollState resultState,
             StackScrollAlgorithmState algorithmState, AmbientState ambientState) {
         int childCount = algorithmState.visibleChildren.size();
-        int shelfIndex = ambientState.getShelfIndex();
+        int belowSpeedBump = ambientState.getSpeedBumpIndex();
         for (int i = 0; i < childCount; i++) {
             View child = algorithmState.visibleChildren.get(i);
             ExpandableViewState childViewState = resultState.getViewStateForView(child);
 
             // The speed bump can also be gone, so equality needs to be taken when comparing
             // indices.
-            childViewState.belowShelf = i >= shelfIndex;
+            childViewState.belowSpeedBump = i >= belowSpeedBump;
         }
+
+    }
+    private void updateShelfState(StackScrollState resultState, AmbientState ambientState) {
         NotificationShelf shelf = ambientState.getShelf();
-        shelf.updateState(resultState, algorithmState, ambientState);
+        shelf.updateState(resultState, ambientState);
     }
 
     private void updateClipping(StackScrollState resultState,
@@ -243,8 +227,6 @@
      */
     private void initAlgorithmState(StackScrollState resultState, StackScrollAlgorithmState state,
             AmbientState ambientState) {
-        state.itemsInBottomStack = 0.0f;
-        state.partialInBottom = 0.0f;
         float bottomOverScroll = ambientState.getOverScrollAmount(false /* onTop */);
 
         int scrollY = ambientState.getScrollY();
@@ -322,72 +304,35 @@
     private void updatePositionsForState(StackScrollState resultState,
             StackScrollAlgorithmState algorithmState, AmbientState ambientState) {
 
-        // The starting position of the bottom stack peek
-        float bottomPeekStart = ambientState.getInnerHeight() - mBottomStackPeekSize;
-
-        // The position where the bottom stack starts.
-        float bottomStackStart = bottomPeekStart - mBottomStackSlowDownLength;
-
         // The y coordinate of the current child.
         float currentYPosition = -algorithmState.scrollY;
         int childCount = algorithmState.visibleChildren.size();
         for (int i = 0; i < childCount; i++) {
             currentYPosition = updateChild(i, resultState, algorithmState, ambientState,
-                    currentYPosition, bottomStackStart);
+                    currentYPosition);
         }
     }
 
     protected float updateChild(int i, StackScrollState resultState,
             StackScrollAlgorithmState algorithmState, AmbientState ambientState,
-            float currentYPosition, float bottomStackStart) {
+            float currentYPosition) {
         ExpandableView child = algorithmState.visibleChildren.get(i);
         ExpandableViewState childViewState = resultState.getViewStateForView(child);
         childViewState.location = ExpandableViewState.LOCATION_UNKNOWN;
         int paddingAfterChild = getPaddingAfterChild(algorithmState, child);
         int childHeight = getMaxAllowedChildHeight(child);
-        int collapsedHeight = child.getCollapsedHeight();
         childViewState.yTranslation = currentYPosition;
-        boolean belowShelf = i >= ambientState.getShelfIndex();
         boolean isDismissView = child instanceof DismissView;
         if (i == 0) {
-            updateFirstChildHeight(child, childViewState, childHeight, algorithmState, ambientState,
-                    belowShelf);
+            updateFirstChildHeight(child, childViewState, childHeight, algorithmState, ambientState);
         }
 
-        // The y position after this element
-        float nextYPosition = currentYPosition + childHeight +
-                paddingAfterChild;
-        if (nextYPosition >= bottomStackStart && belowShelf && !isDismissView) {
-            // Case 1:
-            // We are in the bottom stack.
-            if (currentYPosition >= bottomStackStart) {
-                // According to the regular scroll view we are fully translated out of the
-                // bottom of the screen so we are fully in the bottom stack
-                updateStateForChildFullyInBottomStack(algorithmState,
-                        bottomStackStart, childViewState, collapsedHeight, ambientState, child);
-            } else {
-                // According to the regular scroll view we are currently translating out of /
-                // into the bottom of the screen
-                updateStateForChildTransitioningInBottom(algorithmState,
-                        bottomStackStart, child, currentYPosition,
-                        childViewState, childHeight);
-            }
+        childViewState.location = ExpandableViewState.LOCATION_MAIN_AREA;
+        if (isDismissView) {
+            childViewState.yTranslation = Math.min(childViewState.yTranslation,
+                    ambientState.getInnerHeight() - childHeight);
         } else {
-            // Case 2:
-            // We are in the regular scroll area.
-            childViewState.location = ExpandableViewState.LOCATION_MAIN_AREA;
-            if (belowShelf) {
-                if (!isDismissView) {
-                    clampPositionToBottomStackStart(childViewState, childViewState.height,
-                            childHeight,
-                            ambientState);
-                } else {
-                    childViewState.yTranslation = Math.min(childViewState.yTranslation,
-                            ambientState.getInnerHeight() - childHeight);
-                }
-            } else {
-                clampPositionToShelf(childViewState, ambientState);
-            }
+            clampPositionToShelf(childViewState, ambientState);
         }
 
         currentYPosition = childViewState.yTranslation + childHeight + paddingAfterChild;
@@ -476,30 +421,6 @@
     }
 
     /**
-     * Clamp the yTranslation of the child down such that its end is at most on the beginning of
-     * the bottom stack.
-     *
-     * @param childViewState the view state of the child
-     * @param childHeight the height of this child
-     * @param minHeight the minumum Height of the View
-     */
-    private void clampPositionToBottomStackStart(ExpandableViewState childViewState,
-            int childHeight, int minHeight, AmbientState ambientState) {
-
-        int bottomStackStart = ambientState.getInnerHeight()
-                - mBottomStackPeekSize - mBottomStackSlowDownLength;
-        int childStart = bottomStackStart - childHeight;
-        if (childStart < childViewState.yTranslation) {
-            float newHeight = bottomStackStart - childViewState.yTranslation;
-            if (newHeight < minHeight) {
-                newHeight = minHeight;
-                childViewState.yTranslation = bottomStackStart - minHeight;
-            }
-            childViewState.height = (int) newHeight;
-        }
-    }
-
-    /**
      * Clamp the height of the child down such that its end is at most on the beginning of
      * the shelf.
      *
@@ -528,58 +449,6 @@
         return child == null? mCollapsedSize : child.getHeight();
     }
 
-    private void updateStateForChildTransitioningInBottom(StackScrollAlgorithmState algorithmState,
-            float transitioningPositionStart, ExpandableView child, float currentYPosition,
-            ExpandableViewState childViewState, int childHeight) {
-
-        // This is the transitioning element on top of bottom stack, calculate how far we are in.
-        algorithmState.partialInBottom = 1.0f - (
-                (transitioningPositionStart - currentYPosition) / (childHeight +
-                        getPaddingAfterChild(algorithmState, child)));
-
-        // the offset starting at the transitionPosition of the bottom stack
-        float offset = mBottomStackIndentationFunctor.getValue(algorithmState.partialInBottom);
-        algorithmState.itemsInBottomStack += algorithmState.partialInBottom;
-        int newHeight = childHeight;
-        if (childHeight > child.getCollapsedHeight()) {
-            newHeight = (int) Math.max(Math.min(transitioningPositionStart + offset -
-                    getPaddingAfterChild(algorithmState, child) - currentYPosition, childHeight),
-                    child.getCollapsedHeight());
-            childViewState.height = newHeight;
-        }
-        childViewState.yTranslation = transitioningPositionStart + offset - newHeight
-                - getPaddingAfterChild(algorithmState, child);
-        childViewState.location = ExpandableViewState.LOCATION_MAIN_AREA;
-    }
-
-    private void updateStateForChildFullyInBottomStack(StackScrollAlgorithmState algorithmState,
-            float transitioningPositionStart, ExpandableViewState childViewState,
-            int collapsedHeight, AmbientState ambientState, ExpandableView child) {
-        float currentYPosition;
-        algorithmState.itemsInBottomStack += 1.0f;
-        if (algorithmState.itemsInBottomStack < MAX_ITEMS_IN_BOTTOM_STACK) {
-            // We are visually entering the bottom stack
-            currentYPosition = transitioningPositionStart
-                    + mBottomStackIndentationFunctor.getValue(algorithmState.itemsInBottomStack)
-                    - getPaddingAfterChild(algorithmState, child);
-            childViewState.location = ExpandableViewState.LOCATION_BOTTOM_STACK_PEEKING;
-        } else {
-            // we are fully inside the stack
-            if (algorithmState.itemsInBottomStack > MAX_ITEMS_IN_BOTTOM_STACK + 2) {
-                childViewState.hidden = true;
-                childViewState.shadowAlpha = 0.0f;
-            } else if (algorithmState.itemsInBottomStack
-                    > MAX_ITEMS_IN_BOTTOM_STACK + 1) {
-                childViewState.shadowAlpha = 1.0f - algorithmState.partialInBottom;
-            }
-            childViewState.location = ExpandableViewState.LOCATION_BOTTOM_STACK_HIDDEN;
-            currentYPosition = ambientState.getInnerHeight();
-        }
-        childViewState.height = collapsedHeight;
-        childViewState.yTranslation = currentYPosition - collapsedHeight;
-    }
-
-
     /**
      * Update the height of the first child i.e clamp it to the bottom stack
      * @param child the child to update
@@ -587,23 +456,15 @@
      * @param childHeight the height of the child
      * @param algorithmState the algorithm state
      * @param ambientState The ambient state of the algorithm
-     * @param belowShelf whether it is below the shelf
      */
     protected void updateFirstChildHeight(ExpandableView child, ExpandableViewState childViewState,
             int childHeight, StackScrollAlgorithmState algorithmState,
-            AmbientState ambientState, boolean belowShelf) {
+            AmbientState ambientState) {
 
-        int bottomStart;
-        if (belowShelf) {
-            // The starting position of the bottom stack peek
-            bottomStart = ambientState.getInnerHeight() - mBottomStackPeekSize -
-                    mBottomStackSlowDownLength;
-        } else {
-            bottomStart = ambientState.getInnerHeight();
-            if (algorithmState.visibleChildren.size() > 1) {
-                bottomStart -= ambientState.getShelf().getIntrinsicHeight()
-                        - mPaddingBetweenElements;
-            }
+        int bottomStart= ambientState.getInnerHeight();
+        if (algorithmState.visibleChildren.size() > 1) {
+            bottomStart -= ambientState.getShelf().getIntrinsicHeight()
+                    - mPaddingBetweenElements;
         }
         bottomStart += ambientState.getScrollY();
             // Collapse and expand the first child while the shade is being expanded
@@ -623,39 +484,19 @@
         int childCount = algorithmState.visibleChildren.size();
         float childrenOnTop = 0.0f;
         for (int i = childCount - 1; i >= 0; i--) {
-            updateChildZValue(i, childCount, childrenOnTop,
+            updateChildZValue(i, childrenOnTop,
                     resultState, algorithmState, ambientState);
         }
     }
 
-    protected void updateChildZValue(int i, int childCount, float childrenOnTop,
+    protected void updateChildZValue(int i, float childrenOnTop,
             StackScrollState resultState, StackScrollAlgorithmState algorithmState,
             AmbientState ambientState) {
         ExpandableView child = algorithmState.visibleChildren.get(i);
         ExpandableViewState childViewState = resultState.getViewStateForView(child);
         int zDistanceBetweenElements = ambientState.getZDistanceBetweenElements();
         float baseZ = ambientState.getBaseZHeight();
-        if (i > (childCount - 1 - algorithmState.itemsInBottomStack)) {
-            // We are in the bottom stack
-            float numItemsAbove = i - (childCount - 1 - algorithmState.itemsInBottomStack);
-            float zSubtraction;
-            if (numItemsAbove <= 1.0f) {
-                float factor = 0.2f;
-                // Lets fade in slower to the threshold to make the shadow fade in look nicer
-                if (numItemsAbove <= factor) {
-                    zSubtraction = FakeShadowView.SHADOW_SIBLING_TRESHOLD
-                            * numItemsAbove * (1.0f / factor);
-                } else {
-                    zSubtraction = FakeShadowView.SHADOW_SIBLING_TRESHOLD
-                            + (numItemsAbove - factor) * (1.0f / (1.0f - factor))
-                            * (zDistanceBetweenElements
-                            - FakeShadowView.SHADOW_SIBLING_TRESHOLD);
-                }
-            } else {
-                zSubtraction = numItemsAbove * zDistanceBetweenElements;
-            }
-            childViewState.zTranslation = baseZ - zSubtraction;
-        } else if (child.mustStayOnScreen()
+        if (child.mustStayOnScreen()
                 && childViewState.yTranslation < ambientState.getTopPadding()
                 + ambientState.getStackTranslation()) {
             if (childrenOnTop != 0.0f) {
@@ -688,25 +529,6 @@
         }
     }
 
-    private boolean isMaxSizeInitialized(ExpandableView child) {
-        if (child instanceof ExpandableNotificationRow) {
-            ExpandableNotificationRow row = (ExpandableNotificationRow) child;
-            return row.isMaxExpandHeightInitialized();
-        }
-        return child == null || child.getWidth() != 0;
-    }
-
-    private View findFirstVisibleChild(ViewGroup container) {
-        int childCount = container.getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            View child = container.getChildAt(i);
-            if (child.getVisibility() != View.GONE) {
-                return child;
-            }
-        }
-        return null;
-    }
-
     public void setIsExpanded(boolean isExpanded) {
         this.mIsExpanded = isExpanded;
     }
@@ -719,16 +541,6 @@
         public int scrollY;
 
         /**
-         * The quantity of items which are in the bottom stack.
-         */
-        public float itemsInBottomStack;
-
-        /**
-         * how far in is the element currently transitioning into the bottom stack
-         */
-        public float partialInBottom;
-
-        /**
          * The children from the host view which are not gone.
          */
         public final ArrayList<ExpandableView> visibleChildren = new ArrayList<ExpandableView>();