Made translation of headers consistent when going into the shelf

Previously the headers weren't moving up similar to the content.
This is now happening.

Fixes: 133258119
Test: atest SystemUITests
Change-Id: I3e8594f6a28234373a7f3a2b26b6522850526816
diff --git a/packages/SystemUI/res/layout/people_strip.xml b/packages/SystemUI/res/layout/people_strip.xml
index c2dbaca..f5ed103 100644
--- a/packages/SystemUI/res/layout/people_strip.xml
+++ b/packages/SystemUI/res/layout/people_strip.xml
@@ -31,13 +31,16 @@
         android:layout_height="match_parent"
         android:layout_marginEnd="8dp"
         android:gravity="bottom"
-        android:orientation="horizontal">
+        android:orientation="horizontal"
+        android:forceHasOverlappingRendering="false"
+        android:clipChildren="false">
 
         <FrameLayout
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:gravity="start|center_vertical"
-            android:layout_weight="1">
+            android:layout_weight="1"
+            android:forceHasOverlappingRendering="false">
 
             <TextView
                 style="@style/TextAppearance.NotificationSectionHeaderButton"
@@ -53,6 +56,7 @@
             android:layout_height="48dp"
             android:padding="8dp"
             android:scaleType="fitCenter"
+            android:forceHasOverlappingRendering="false"
         />
 
         <ImageView
@@ -60,6 +64,7 @@
             android:layout_height="48dp"
             android:padding="8dp"
             android:scaleType="fitCenter"
+            android:forceHasOverlappingRendering="false"
         />
 
         <ImageView
@@ -67,6 +72,7 @@
             android:layout_height="48dp"
             android:padding="8dp"
             android:scaleType="fitCenter"
+            android:forceHasOverlappingRendering="false"
         />
 
         <ImageView
@@ -74,6 +80,7 @@
             android:layout_height="48dp"
             android:padding="8dp"
             android:scaleType="fitCenter"
+            android:forceHasOverlappingRendering="false"
         />
 
         <ImageView
@@ -81,6 +88,7 @@
             android:layout_height="48dp"
             android:padding="8dp"
             android:scaleType="fitCenter"
+            android:forceHasOverlappingRendering="false"
         />
 
     </LinearLayout>
diff --git a/packages/SystemUI/res/layout/status_bar_notification_section_header.xml b/packages/SystemUI/res/layout/status_bar_notification_section_header.xml
index 0043d7a..44c409e 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_section_header.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_section_header.xml
@@ -32,6 +32,8 @@
         android:layout_gravity="bottom"
         android:gravity="center_vertical"
         android:orientation="horizontal"
+        android:forceHasOverlappingRendering="false"
+        android:clipChildren="false"
         >
         <include layout="@layout/status_bar_notification_section_header_contents"/>
     </LinearLayout>
diff --git a/packages/SystemUI/res/layout/status_bar_notification_section_header_contents.xml b/packages/SystemUI/res/layout/status_bar_notification_section_header_contents.xml
index df4b047..3b9c44d 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_section_header_contents.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_section_header_contents.xml
@@ -27,6 +27,7 @@
             android:id="@+id/header_label"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
+            android:forceHasOverlappingRendering="false"
             android:text="@string/notification_section_header_gentle"
         />
 
@@ -41,5 +42,6 @@
         android:tint="?attr/wallpaperTextColor"
         android:tintMode="src_in"
         android:visibility="gone"
+        android:forceHasOverlappingRendering="false"
     />
 </merge>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 1c2404f..5880fe1 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -181,8 +181,8 @@
     <!-- Vertical translation of pulsing notification animations -->
     <dimen name="pulsing_notification_appear_translation">10dp</dimen>
 
-    <!-- The amount the content shifts upwards when transforming into the icon -->
-    <dimen name="notification_icon_transform_content_shift">32dp</dimen>
+    <!-- The amount the content shifts upwards when transforming into the shelf -->
+    <dimen name="shelf_transform_content_shift">32dp</dimen>
 
     <!-- The padding on the bottom of the notifications on the keyguard -->
     <dimen name="keyguard_indication_bottom_padding">12sp</dimen>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 819300a..1f7ce46 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -291,14 +291,13 @@
             int clipTop = updateNotificationClipHeight(child, notificationClipEnd, notGoneIndex);
             clipTopAmount = Math.max(clipTop, clipTopAmount);
 
+
+            float inShelfAmount = updateShelfTransformation(child, expandAmount, scrolling,
+                    scrollingFast, expandingAnimated, isLastChild);
             // If the current row is an ExpandableNotificationRow, update its color, roundedness,
             // and icon state.
             if (child instanceof ExpandableNotificationRow) {
                 ExpandableNotificationRow expandableRow = (ExpandableNotificationRow) child;
-
-                float inShelfAmount = updateIconAppearance(expandableRow, expandAmount, scrolling,
-                        scrollingFast,
-                        expandingAnimated, isLastChild);
                 numViewsInShelf += inShelfAmount;
                 int ownColorUntinted = expandableRow.getBackgroundColorWithoutTint();
                 if (rowTranslationY >= shelfStart && mNotGoneIndex == -1) {
@@ -525,31 +524,28 @@
     }
 
     /**
-     * @return the icon amount how much this notification is in the shelf;
+     * @return the amount how much this notification is in the shelf
      */
-    private float updateIconAppearance(ExpandableNotificationRow row, float expandAmount,
+    private float updateShelfTransformation(ExpandableView view, float expandAmount,
             boolean scrolling, boolean scrollingFast, boolean expandingAnimated,
             boolean isLastChild) {
-        StatusBarIconView icon = row.getEntry().expandedIcon;
+        StatusBarIconView icon = view.getShelfIcon();
         NotificationIconContainer.IconState iconState = getIconState(icon);
-        if (iconState == null) {
-            return 0.0f;
-        }
 
         // Let calculate how much the view is in the shelf
-        float viewStart = row.getTranslationY();
-        int fullHeight = row.getActualHeight() + mPaddingBetweenElements;
+        float viewStart = view.getTranslationY();
+        int fullHeight = view.getActualHeight() + mPaddingBetweenElements;
         float iconTransformDistance = getIntrinsicHeight() * 1.5f;
         iconTransformDistance *= NotificationUtils.interpolate(1.f, 1.5f, expandAmount);
         iconTransformDistance = Math.min(iconTransformDistance, fullHeight);
         if (isLastChild) {
-            fullHeight = Math.min(fullHeight, row.getMinHeight() - getIntrinsicHeight());
-            iconTransformDistance = Math.min(iconTransformDistance, row.getMinHeight()
+            fullHeight = Math.min(fullHeight, view.getMinHeight() - getIntrinsicHeight());
+            iconTransformDistance = Math.min(iconTransformDistance, view.getMinHeight()
                     - getIntrinsicHeight());
         }
         float viewEnd = viewStart + fullHeight;
         // TODO: fix this check for anchor scrolling.
-        if (expandingAnimated && mAmbientState.getScrollY() == 0
+        if (iconState != null && expandingAnimated && mAmbientState.getScrollY() == 0
                 && !mAmbientState.isOnKeyguard() && !iconState.isLastExpandIcon) {
             // We are expanding animated. Because we switch to a linear interpolation in this case,
             // the last icon may be stuck in between the shelf position and the notification
@@ -559,10 +555,10 @@
             // We need to persist this, since after the expansion, the behavior should still be the
             // same.
             float position = mAmbientState.getIntrinsicPadding()
-                    + mHostLayout.getPositionInLinearLayout(row);
+                    + mHostLayout.getPositionInLinearLayout(view);
             int maxShelfStart = mMaxLayoutHeight - getIntrinsicHeight();
-            if (position < maxShelfStart && position + row.getIntrinsicHeight() >= maxShelfStart
-                    && row.getTranslationY() < position) {
+            if (position < maxShelfStart && position + view.getIntrinsicHeight() >= maxShelfStart
+                    && view.getTranslationY() < position) {
                 iconState.isLastExpandIcon = true;
                 iconState.customTransformHeight = NO_VALUE;
                 // Let's check if we're close enough to snap into the shelf
@@ -577,16 +573,16 @@
             }
         }
         float fullTransitionAmount;
-        float iconTransitionAmount;
+        float transitionAmount;
         float shelfStart = getTranslationY();
-        if (iconState.hasCustomTransformHeight()) {
+        if (iconState != null && iconState.hasCustomTransformHeight()) {
             fullHeight = iconState.customTransformHeight;
             iconTransformDistance = iconState.customTransformHeight;
         }
         boolean fullyInOrOut = true;
-        if (viewEnd >= shelfStart && (!mAmbientState.isUnlockHintRunning() || row.isInShelf())
+        if (viewEnd >= shelfStart && (!mAmbientState.isUnlockHintRunning() || view.isInShelf())
                 && (mAmbientState.isShadeExpanded()
-                        || (!row.isPinned() && !row.isHeadsUpAnimatingAway()))) {
+                        || (!view.isPinned() && !view.isHeadsUpAnimatingAway()))) {
             if (viewStart < shelfStart) {
                 float fullAmount = (shelfStart - viewStart) / fullHeight;
                 fullAmount = Math.min(1.0f, fullAmount);
@@ -596,88 +592,98 @@
                         interpolatedAmount, fullAmount, expandAmount);
                 fullTransitionAmount = 1.0f - interpolatedAmount;
 
-                iconTransitionAmount = (shelfStart - viewStart) / iconTransformDistance;
-                iconTransitionAmount = Math.min(1.0f, iconTransitionAmount);
-                iconTransitionAmount = 1.0f - iconTransitionAmount;
+                transitionAmount = (shelfStart - viewStart) / iconTransformDistance;
+                transitionAmount = Math.min(1.0f, transitionAmount);
+                transitionAmount = 1.0f - transitionAmount;
                 fullyInOrOut = false;
             } else {
                 fullTransitionAmount = 1.0f;
-                iconTransitionAmount = 1.0f;
+                transitionAmount = 1.0f;
             }
         } else {
             fullTransitionAmount = 0.0f;
-            iconTransitionAmount = 0.0f;
+            transitionAmount = 0.0f;
         }
-        if (fullyInOrOut && !expandingAnimated && iconState.isLastExpandIcon) {
+        if (iconState != null && fullyInOrOut && !expandingAnimated && iconState.isLastExpandIcon) {
             iconState.isLastExpandIcon = false;
             iconState.customTransformHeight = NO_VALUE;
         }
-        updateIconPositioning(row, iconTransitionAmount, fullTransitionAmount,
+        updateIconPositioning(view, transitionAmount, fullTransitionAmount,
                 iconTransformDistance, scrolling, scrollingFast, expandingAnimated, isLastChild);
         return fullTransitionAmount;
     }
 
-    private void updateIconPositioning(ExpandableNotificationRow row, float iconTransitionAmount,
+    private void updateIconPositioning(ExpandableView view, float iconTransitionAmount,
             float fullTransitionAmount, float iconTransformDistance, boolean scrolling,
             boolean scrollingFast, boolean expandingAnimated, boolean isLastChild) {
-        StatusBarIconView icon = row.getEntry().expandedIcon;
+        StatusBarIconView icon = view.getShelfIcon();
         NotificationIconContainer.IconState iconState = getIconState(icon);
+        float contentTransformationAmount;
         if (iconState == null) {
-            return;
-        }
-        boolean forceInShelf = iconState.isLastExpandIcon && !iconState.hasCustomTransformHeight();
-        float clampedAmount = iconTransitionAmount > 0.5f ? 1.0f : 0.0f;
-        if (clampedAmount == fullTransitionAmount) {
-            iconState.noAnimations = (scrollingFast || expandingAnimated) && !forceInShelf;
-            iconState.useFullTransitionAmount = iconState.noAnimations
-                || (!ICON_ANMATIONS_WHILE_SCROLLING && fullTransitionAmount == 0.0f && scrolling);
-            iconState.useLinearTransitionAmount = !ICON_ANMATIONS_WHILE_SCROLLING
-                    && fullTransitionAmount == 0.0f && !mAmbientState.isExpansionChanging();
-            iconState.translateContent = mMaxLayoutHeight - getTranslationY()
-                    - getIntrinsicHeight() > 0;
-        }
-        if (!forceInShelf && (scrollingFast || (expandingAnimated
-                && iconState.useFullTransitionAmount && !ViewState.isAnimatingY(icon)))) {
-            iconState.cancelAnimations(icon);
-            iconState.useFullTransitionAmount = true;
-            iconState.noAnimations = true;
-        }
-        if (iconState.hasCustomTransformHeight()) {
-            iconState.useFullTransitionAmount = true;
-        }
-        if (iconState.isLastExpandIcon) {
-            iconState.translateContent = false;
-        }
-        float transitionAmount;
-        if (mAmbientState.isHiddenAtAll() && !row.isInShelf()) {
-            transitionAmount = mAmbientState.isFullyHidden() ? 1 : 0;
-        } else if (isLastChild || !USE_ANIMATIONS_WHEN_OPENING || iconState.useFullTransitionAmount
-                || iconState.useLinearTransitionAmount) {
-            transitionAmount = iconTransitionAmount;
+            contentTransformationAmount = iconTransitionAmount;
         } else {
-            // We take the clamped position instead
-            transitionAmount = clampedAmount;
-            iconState.needsCannedAnimation = iconState.clampedAppearAmount != clampedAmount
-                    && !mNoAnimationsInThisFrame;
-        }
-        iconState.iconAppearAmount = !USE_ANIMATIONS_WHEN_OPENING
+            boolean forceInShelf =
+                    iconState.isLastExpandIcon && !iconState.hasCustomTransformHeight();
+            float clampedAmount = iconTransitionAmount > 0.5f ? 1.0f : 0.0f;
+            if (clampedAmount == fullTransitionAmount) {
+                iconState.noAnimations = (scrollingFast || expandingAnimated) && !forceInShelf;
+                iconState.useFullTransitionAmount = iconState.noAnimations
+                        || (!ICON_ANMATIONS_WHILE_SCROLLING && fullTransitionAmount == 0.0f
+                        && scrolling);
+                iconState.useLinearTransitionAmount = !ICON_ANMATIONS_WHILE_SCROLLING
+                        && fullTransitionAmount == 0.0f && !mAmbientState.isExpansionChanging();
+                iconState.translateContent = mMaxLayoutHeight - getTranslationY()
+                        - getIntrinsicHeight() > 0;
+            }
+            if (!forceInShelf && (scrollingFast || (expandingAnimated
+                    && iconState.useFullTransitionAmount && !ViewState.isAnimatingY(icon)))) {
+                iconState.cancelAnimations(icon);
+                iconState.useFullTransitionAmount = true;
+                iconState.noAnimations = true;
+            }
+            if (iconState.hasCustomTransformHeight()) {
+                iconState.useFullTransitionAmount = true;
+            }
+            if (iconState.isLastExpandIcon) {
+                iconState.translateContent = false;
+            }
+            float transitionAmount;
+            if (mAmbientState.isHiddenAtAll() && !view.isInShelf()) {
+                transitionAmount = mAmbientState.isFullyHidden() ? 1 : 0;
+            } else if (isLastChild || !USE_ANIMATIONS_WHEN_OPENING
                     || iconState.useFullTransitionAmount
-                ? fullTransitionAmount
-                : transitionAmount;
-        iconState.clampedAppearAmount = clampedAmount;
-        float contentTransformationAmount = !row.isAboveShelf() && !row.showingPulsing()
+                    || iconState.useLinearTransitionAmount) {
+                transitionAmount = iconTransitionAmount;
+            } else {
+                // We take the clamped position instead
+                transitionAmount = clampedAmount;
+                iconState.needsCannedAnimation = iconState.clampedAppearAmount != clampedAmount
+                        && !mNoAnimationsInThisFrame;
+            }
+            iconState.iconAppearAmount = !USE_ANIMATIONS_WHEN_OPENING
+                    || iconState.useFullTransitionAmount
+                    ? fullTransitionAmount
+                    : transitionAmount;
+            iconState.clampedAppearAmount = clampedAmount;
+            contentTransformationAmount = !view.isAboveShelf() && !view.showingPulsing()
                     && (isLastChild || iconState.translateContent)
-                ? iconTransitionAmount
-                : 0.0f;
-        row.setContentTransformationAmount(contentTransformationAmount, isLastChild);
-        setIconTransformationAmount(row, transitionAmount, iconTransformDistance,
-                clampedAmount != transitionAmount, isLastChild);
+                    ? iconTransitionAmount
+                    : 0.0f;
+            setIconTransformationAmount(view, transitionAmount, iconTransformDistance,
+                    clampedAmount != transitionAmount, isLastChild);
+        }
+        view.setContentTransformationAmount(contentTransformationAmount, isLastChild);
     }
 
-    private void setIconTransformationAmount(ExpandableNotificationRow row,
+    private void setIconTransformationAmount(ExpandableView view,
             float transitionAmount, float iconTransformDistance, boolean usingLinearInterpolation,
             boolean isLastChild) {
-        StatusBarIconView icon = row.getEntry().expandedIcon;
+        if (!(view instanceof ExpandableNotificationRow)) {
+            return;
+        }
+        ExpandableNotificationRow row = (ExpandableNotificationRow) view;
+
+        StatusBarIconView icon = row.getShelfIcon();
         NotificationIconContainer.IconState iconState = getIconState(icon);
 
         View rowIcon = row.getNotificationIcon();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 5008133..617f08b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -138,7 +138,6 @@
     private LayoutListener mLayoutListener;
     private RowContentBindStage mRowContentBindStage;
     private int mIconTransformContentShift;
-    private int mIconTransformContentShiftNoIcon;
     private int mMaxHeadsUpHeightBeforeN;
     private int mMaxHeadsUpHeightBeforeP;
     private int mMaxHeadsUpHeight;
@@ -307,10 +306,8 @@
     private boolean mHeadsupDisappearRunning;
     private View mChildAfterViewWhenDismissed;
     private View mGroupParentWhenDismissed;
-    private float mContentTransformationAmount;
     private boolean mIconsVisible = true;
     private boolean mAboveShelf;
-    private boolean mIsLastChild;
     private Runnable mOnDismissRunnable;
     private boolean mIsLowPriority;
     private boolean mIsColorized;
@@ -1485,18 +1482,19 @@
         updateIconVisibilities();
     }
 
-    private void updateContentTransformation() {
+    @Override
+    protected void updateContentTransformation() {
         if (mExpandAnimationRunning) {
             return;
         }
-        float contentAlpha;
-        float translationY = -mContentTransformationAmount * mIconTransformContentShift;
-        if (mIsLastChild) {
-            contentAlpha = 1.0f - mContentTransformationAmount;
-            contentAlpha = Math.min(contentAlpha / 0.5f, 1.0f);
-            contentAlpha = Interpolators.ALPHA_OUT.getInterpolation(contentAlpha);
-            translationY *= 0.4f;
-        } else {
+        super.updateContentTransformation();
+    }
+
+    @Override
+    protected void applyContentTransformation(float contentAlpha, float translationY) {
+        super.applyContentTransformation(contentAlpha, translationY);
+        if (!mIsLastChild) {
+            // Don't fade views unless we're last
             contentAlpha = 1.0f;
         }
         for (NotificationContentView l : mLayouts) {
@@ -1649,8 +1647,6 @@
         Resources res = getResources();
         mIncreasedPaddingBetweenElements = res.getDimensionPixelSize(
                 R.dimen.notification_divider_height_increased);
-        mIconTransformContentShiftNoIcon = res.getDimensionPixelSize(
-                R.dimen.notification_icon_transform_content_shift);
         mEnableNonGroupedNotificationExpand =
                 res.getBoolean(R.bool.config_enableNonGroupedNotificationExpand);
         mShowGroupBackgroundWhenExpanded =
@@ -2114,6 +2110,11 @@
     }
 
     @Override
+    public StatusBarIconView getShelfIcon() {
+        return getEntry().expandedIcon;
+    }
+
+    @Override
     protected boolean shouldClipToActualHeight() {
         return super.shouldClipToActualHeight() && !mExpandAnimationRunning;
     }
@@ -2449,11 +2450,16 @@
             CachingIconView icon = notificationHeader.getIcon();
             mIconTransformContentShift = getRelativeTopPadding(icon) + icon.getHeight();
         } else {
-            mIconTransformContentShift = mIconTransformContentShiftNoIcon;
+            mIconTransformContentShift = mContentShift;
         }
     }
 
     @Override
+    protected float getContentTransformationShift() {
+        return mIconTransformContentShift;
+    }
+
+    @Override
     public void notifyHeightChanged(boolean needsAnimation) {
         super.notifyHeightChanged(needsAnimation);
         getShowingLayout().requestSelectLayout(needsAnimation || isUserLocked());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
index 241285a..a9f72ff 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
@@ -18,6 +18,7 @@
 
 import android.animation.AnimatorListenerAdapter;
 import android.content.Context;
+import android.content.res.Configuration;
 import android.graphics.Paint;
 import android.graphics.Rect;
 import android.util.AttributeSet;
@@ -28,6 +29,9 @@
 import androidx.annotation.Nullable;
 
 import com.android.systemui.Dumpable;
+import com.android.systemui.Interpolators;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.StatusBarIconView;
 import com.android.systemui.statusbar.notification.stack.ExpandableViewState;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
 
@@ -58,11 +62,26 @@
     private ViewGroup mTransientContainer;
     private boolean mInShelf;
     private boolean mTransformingInShelf;
+    protected float mContentTransformationAmount;
+    protected boolean mIsLastChild;
+    protected int mContentShift;
     private final ExpandableViewState mViewState;
 
     public ExpandableView(Context context, AttributeSet attrs) {
         super(context, attrs);
         mViewState = createExpandableViewState();
+        initDimens();
+    }
+
+    private void initDimens() {
+        mContentShift = getResources().getDimensionPixelSize(
+                R.dimen.shelf_transform_content_shift);
+    }
+
+    @Override
+    protected void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        initDimens();
     }
 
     @Override
@@ -594,7 +613,7 @@
 
     /**
      * @return whether the current view doesn't add height to the overall content. This means that
-     * if it is added to a list of items, it's content will still have the same height.
+     * if it is added to a list of items, its content will still have the same height.
      * An example is the notification shelf, that is always placed on top of another view.
      */
     public boolean hasNoContentHeight() {
@@ -612,6 +631,59 @@
         return mInShelf;
     }
 
+    public @Nullable StatusBarIconView getShelfIcon() {
+        return null;
+    }
+
+    /**
+     * Set how much this notification is transformed into the shelf.
+     *
+     * @param contentTransformationAmount A value from 0 to 1 indicating how much we are transformed
+     *                                 to the content away
+     * @param isLastChild is this the last child in the list. If true, then the transformation is
+     *                    different since its content fades out.
+     */
+    public void setContentTransformationAmount(float contentTransformationAmount,
+            boolean isLastChild) {
+        boolean changeTransformation = isLastChild != mIsLastChild;
+        changeTransformation |= mContentTransformationAmount != contentTransformationAmount;
+        mIsLastChild = isLastChild;
+        mContentTransformationAmount = contentTransformationAmount;
+        if (changeTransformation) {
+            updateContentTransformation();
+        }
+    }
+
+    /**
+     * Update the content representation based on the amount we are transformed into the shelf.
+     */
+    protected void updateContentTransformation() {
+        float translationY = -mContentTransformationAmount * getContentTransformationShift();
+        float contentAlpha = 1.0f - mContentTransformationAmount;
+        contentAlpha = Math.min(contentAlpha / 0.5f, 1.0f);
+        contentAlpha = Interpolators.ALPHA_OUT.getInterpolation(contentAlpha);
+        if (mIsLastChild) {
+            translationY *= 0.4f;
+        }
+        applyContentTransformation(contentAlpha, translationY);
+    }
+
+    /**
+     * @return how much the content shifts up when going into the shelf
+     */
+    protected float getContentTransformationShift() {
+        return mContentShift;
+    }
+
+    /**
+     * Apply the contentTransformation when going into the shelf.
+     *
+     * @param contentAlpha The alpha that should be applied
+     * @param translationY the translationY that should be applied
+     */
+    protected void applyContentTransformation(float contentAlpha, float translationY) {
+    }
+
     /**
      * @param transformingInShelf whether the view is currently transforming into the shelf in an
      *                            animated way
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java
index 0d3c490..82e5f0a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java
@@ -49,6 +49,7 @@
 
     public StackScrollerDecorView(Context context, AttributeSet attrs) {
         super(context, attrs);
+        setClipChildren(false);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt
index 9899f3f..1b4f98f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt
@@ -80,6 +80,15 @@
         return true
     }
 
+    override fun applyContentTransformation(contentAlpha: Float, translationY: Float) {
+        super.applyContentTransformation(contentAlpha, translationY)
+        for (i in 0 until contents.childCount) {
+            val view = contents.getChildAt(i)
+            view.alpha = contentAlpha
+            view.translationY = translationY
+        }
+    }
+
     private inner class PersonDataListenerImpl(val avatarView: ImageView) :
             DataListener<PersonViewModel?> {
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SectionHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SectionHeaderView.java
index bffeaeb..deb5532 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SectionHeaderView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SectionHeaderView.java
@@ -108,6 +108,15 @@
         mLabelView.setOnClickListener(listener);
     }
 
+    @Override
+    protected void applyContentTransformation(float contentAlpha, float translationY) {
+        super.applyContentTransformation(contentAlpha, translationY);
+        mLabelView.setAlpha(contentAlpha);
+        mLabelView.setTranslationY(translationY);
+        mClearAllButton.setAlpha(contentAlpha);
+        mClearAllButton.setTranslationY(translationY);
+    }
+
     /** Fired when the user clicks on the "X" button on the far right of the header. */
     void setOnClearAllClickListener(View.OnClickListener listener) {
         mOnClearClickListener = listener;