Introduced the notification header

In the new grouping model we don't have a dedicated expand button
anymore but only the notification header.

Bug: 24866646
Change-Id: I2e4bc82e502fde951a71b61cd81347c44b9637f6
diff --git a/packages/SystemUI/res/drawable/ic_collapse_children.xml b/packages/SystemUI/res/drawable/ic_collapse_children.xml
deleted file mode 100644
index b0ce1e6..0000000
--- a/packages/SystemUI/res/drawable/ic_collapse_children.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<!--
-  ~ Copyright (C) 2015 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
-  -->
-
-<inset xmlns:android="http://schemas.android.com/apk/res/android"
-       android:insetTop="2dp"
-       android:drawable="@drawable/ic_expand_less"/>
diff --git a/packages/SystemUI/res/drawable/ic_expand_children.xml b/packages/SystemUI/res/drawable/ic_expand_children.xml
deleted file mode 100644
index 1762be4..0000000
--- a/packages/SystemUI/res/drawable/ic_expand_children.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<!--
-  ~ Copyright (C) 2015 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
-  -->
-<inset xmlns:android="http://schemas.android.com/apk/res/android"
-       android:insetTop="2dp"
-       android:drawable="@drawable/ic_expand_more"/>
diff --git a/packages/SystemUI/res/drawable/notification_expand_more.xml b/packages/SystemUI/res/drawable/notification_expand_more.xml
new file mode 100644
index 0000000..5aa7937
--- /dev/null
+++ b/packages/SystemUI/res/drawable/notification_expand_more.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2015 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="22.0dp"
+    android:height="22.0dp"
+    android:viewportWidth="24.0"
+    android:viewportHeight="24.0">
+    <path
+        android:pathData="M16.600000,8.600000l-4.600000,4.599999 -4.600000,-4.599999 -1.400000,1.400000 6.000000,6.000000 6.000000,-6.000000z"
+        android:fillColor="#FF000000"/>
+</vector>
diff --git a/packages/SystemUI/res/layout/notification_collapse_button.xml b/packages/SystemUI/res/layout/notification_collapse_button.xml
deleted file mode 100644
index 3ec5f63..0000000
--- a/packages/SystemUI/res/layout/notification_collapse_button.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2015 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
-  -->
-<FrameLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="@dimen/notification_bottom_decor_height">
-    <TextView
-        android:id="@+id/notification_expand_button"
-        android:layout_width="wrap_content"
-        android:layout_height="@dimen/notification_bottom_decor_height"
-        android:background="@null"
-        android:layout_gravity="top|center_horizontal"
-        android:gravity="center_vertical|center_horizontal"
-        android:textAppearance="@*android:style/TextAppearance.Material.Notification.Title"
-        android:text="@string/notification_collapse_button_text"
-        android:drawableEnd="@drawable/ic_collapse_children"
-        android:drawablePadding="1dp"
-        />
-</FrameLayout>
diff --git a/packages/SystemUI/res/layout/notification_expand_button.xml b/packages/SystemUI/res/layout/notification_expand_button.xml
deleted file mode 100644
index 3c478f7..0000000
--- a/packages/SystemUI/res/layout/notification_expand_button.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2015 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
-  -->
-
-<FrameLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="@dimen/notification_bottom_decor_height">
-    <TextView
-        android:id="@+id/notification_expand_button"
-        android:layout_width="wrap_content"
-        android:layout_height="@dimen/notification_bottom_decor_height"
-        android:background="@null"
-        android:layout_gravity="top|center_horizontal"
-        android:gravity="center_vertical|center_horizontal"
-        android:textAppearance="@*android:style/TextAppearance.Material.Notification.Title"
-        android:text="@string/notification_expand_button_text"
-        android:drawableEnd="@drawable/ic_expand_children"
-        android:drawablePadding="1dp"
-        />
-    <com.android.systemui.statusbar.AlphaOptimizedView
-        android:id="@+id/notification_expand_divider"
-        android:layout_width="match_parent"
-        android:layout_height="1dp"
-        android:layout_gravity="top|center"
-        android:background="@*android:drawable/notification_template_divider" />
-</FrameLayout>
diff --git a/packages/SystemUI/res/layout/notification_header.xml b/packages/SystemUI/res/layout/notification_header.xml
new file mode 100644
index 0000000..3475d00
--- /dev/null
+++ b/packages/SystemUI/res/layout/notification_header.xml
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 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
+  -->
+
+<com.android.systemui.statusbar.notification.NotificationHeaderView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="@dimen/notification_header_height"
+    android:clipChildren="false">
+    <LinearLayout
+        android:orientation="horizontal"
+        android:layout_width="wrap_content"
+        android:layout_height="@dimen/notification_header_height"
+        android:layout_gravity="start"
+        android:gravity="center_vertical"
+        android:paddingStart="@dimen/notification_content_margin_start">
+        <ImageView
+            android:id="@+id/header_notification_icon"
+            android:layout_width="24dp"
+            android:layout_height="24dp"
+            android:layout_marginEnd="4dp"
+            />
+        <TextView
+            android:id="@+id/number_of_children"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textAppearance="@*android:style/TextAppearance.Material.Notification"
+            android:layout_marginEnd="2dp"
+            android:layout_marginStart="1dp"
+            />
+        <TextView
+            android:id="@+id/app_name_text"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textAppearance="@style/TextAppearance.Material.Notification.HeaderTitle"
+            android:layout_marginStart="4dp"
+            android:layout_marginEnd="8dp"
+            />
+        <TextView
+            android:id="@+id/app_title_sub_text_divider"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textAppearance="@style/TextAppearance.Material.Notification.HeaderTitle"
+            android:layout_marginEnd="8dp"
+            android:text="@string/notification_header_divider_symbol"/>
+        <TextView
+            android:id="@+id/title_sub_text"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textAppearance="@style/TextAppearance.Material.Notification.HeaderTitle"
+            android:layout_marginEnd="8dp" />
+        <TextView
+            android:id="@+id/post_time"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="end|center_vertical"
+            android:textAppearance="@*android:style/TextAppearance.Material.Notification.Time"
+            android:paddingEnd="8dp"
+            />
+    </LinearLayout>
+    <ImageButton
+        android:id="@+id/notification_expand_button"
+        android:background="@null"
+        android:layout_width="48dp"
+        android:layout_height="48dp"
+        android:layout_gravity="end|center_vertical"
+        android:src="@drawable/notification_expand_more"
+        android:layout_marginEnd="8dp"
+        />
+</com.android.systemui.statusbar.notification.NotificationHeaderView>
diff --git a/packages/SystemUI/res/layout/status_bar_notification_row.xml b/packages/SystemUI/res/layout/status_bar_notification_row.xml
index ea7ce96..b9088ec 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_row.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_row.xml
@@ -61,11 +61,11 @@
         />
 
     <ViewStub
-        android:layout="@layout/notification_expand_button"
-        android:id="@+id/more_button_stub"
-        android:inflatedId="@+id/notification_more_button_container"
+        android:layout="@layout/notification_header"
+        android:id="@+id/notification_header_stub"
+        android:inflatedId="@+id/notification_header"
         android:layout_width="match_parent"
-        android:layout_height="@dimen/notification_bottom_decor_height"
+        android:layout_height="@dimen/notification_header_height"
         />
 
     <ViewStub
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index a4137b9..9fd82ed 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -333,8 +333,8 @@
     <!-- radius of the corners of the material rounded rect background but negative-->
     <dimen name="notification_material_rounded_rect_radius_negative">-2dp</dimen>
 
-    <!-- height of the bottom decor below the notification if present (eg. an expand action) -->
-    <dimen name="notification_bottom_decor_height">48dp</dimen>
+    <!-- height of notification header view if present -->
+    <dimen name="notification_header_height">32dp</dimen>
 
     <!-- The padding between notification children -->
     <dimen name="notification_children_padding">2dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 7c86f96..844bab3 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -751,6 +751,9 @@
     <!-- Text for overflow card on Keyguard when there is not enough space for all notifications on Keyguard. [CHAR LIMIT=1] -->
     <string name="keyguard_more_overflow_text">+<xliff:g id="number_of_notifications" example="5">%d</xliff:g></string>
 
+    <!-- The divider symbol between different parts of the notification header. not translatable [CHAR LIMIT=1] -->
+    <string name="notification_header_divider_symbol" translatable="false">•</string>
+
     <!-- An explanation for the visual speed bump in the notifications, which will appear when you click on it. [CHAR LIMIT=50] -->
     <string name="speed_bump_explanation">Less urgent notifications below</string>
 
@@ -978,12 +981,6 @@
     <!-- continue action for notification educating the user about enabling notifications on the lockscreen. [CHAR LIMIT=20] -->
     <string name="hidden_notifications_setup">Set up</string>
 
-    <!-- Text for the button to expand the notifications to show notification children [CHAR LIMIT=20] -->
-    <string name="notification_expand_button_text">See all</string>
-
-    <!-- Text for the button to expand the notifications to hide notification children [CHAR LIMIT=20] -->
-    <string name="notification_collapse_button_text">Hide all</string>
-
     <!-- Accessibility string for current zen mode and selected exit condition. A template that simply concatenates existing mode string and the current condition description. [CHAR LIMIT=20] -->
     <string name="zen_mode_and_condition"><xliff:g id="zen_mode" example="Priority interruptions only">%1$s</xliff:g>. <xliff:g id="exit_condition" example="For one hour">%2$s</xliff:g></string>
 
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 8241ddf..9e942f0 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -244,6 +244,10 @@
         <item name="android:textColor">#60000000</item>
     </style>
 
+    <style name="TextAppearance.Material.Notification.HeaderTitle"
+        parent="@*android:style/TextAppearance.Material.Notification.Info">
+    </style>
+
     <style name="SearchPanelCircle">
         <item name="android:layout_width">match_parent</item>
         <item name="android:layout_height">match_parent</item>
diff --git a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
index 1dca149..5e1974e 100644
--- a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
@@ -138,11 +138,11 @@
         }
         public void setHeight(float h) {
             if (DEBUG_SCALE) Log.v(TAG, "SetHeight: setting to " + h);
-            mView.setContentHeight((int) h);
+            mView.setActualHeight((int) h);
             mCurrentHeight = h;
         }
         public float getHeight() {
-            return mView.getContentHeight();
+            return mView.getActualHeight();
         }
         public int getNaturalHeight(int maximum) {
             return Math.min(maximum, mView.getMaxContentHeight());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 2c16f81..ec22b9f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -891,8 +891,7 @@
     private void bindGuts(ExpandableNotificationRow row) {
         row.inflateGuts();
         final StatusBarNotification sbn = row.getStatusBarNotification();
-        PackageManager pmUser = getPackageManagerForUser(
-                sbn.getUser().getIdentifier());
+        PackageManager pmUser = getPackageManagerForUser(mContext, sbn.getUser().getIdentifier());
         row.setTag(sbn.getPackageName());
         final View guts = row.getGuts();
         final String pkg = sbn.getPackageName();
@@ -1270,7 +1269,7 @@
     }
 
     protected boolean inflateViews(Entry entry, ViewGroup parent) {
-        PackageManager pmUser = getPackageManagerForUser(
+        PackageManager pmUser = getPackageManagerForUser(mContext,
                 entry.notification.getUser().getIdentifier());
 
         int maxHeight = mRowMaxHeight;
@@ -1502,7 +1501,7 @@
             row.setUserExpanded(userExpanded);
         }
         row.setUserLocked(userLocked);
-        row.setStatusBarNotification(entry.notification);
+        row.setEntry(entry);
         applyRemoteInput(entry);
         return true;
     }
@@ -2113,7 +2112,7 @@
         // update the contentIntent
         mNotificationClicker.register(entry.row, sbn);
 
-        entry.row.setStatusBarNotification(sbn);
+        entry.row.setEntry(entry);
         entry.row.notifyContentUpdated();
         entry.row.resetHeight();
 
@@ -2207,15 +2206,15 @@
      * @return a PackageManger for userId or if userId is < 0 (USER_ALL etc) then
      *         return PackageManager for mContext
      */
-    protected PackageManager getPackageManagerForUser(int userId) {
-        Context contextForUser = mContext;
+    public static PackageManager getPackageManagerForUser(Context context, int userId) {
+        Context contextForUser = context;
         // UserHandle defines special userId as negative values, e.g. USER_ALL
         if (userId >= 0) {
             try {
                 // Create a context for the correct user so if a package isn't installed
                 // for user 0 we can still load information about the package.
                 contextForUser =
-                        mContext.createPackageContextAsUser(mContext.getPackageName(),
+                        context.createPackageContextAsUser(context.getPackageName(),
                         Context.CONTEXT_RESTRICTED,
                         new UserHandle(userId));
             } catch (NameNotFoundException e) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
index 517572d..14051916 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
@@ -177,16 +177,16 @@
             overshoot *= (1 - RUBBERBAND_FACTOR_STATIC);
             rubberband -= overshoot;
         }
-        child.setContentHeight((int) (child.getMinHeight() + rubberband));
+        child.setActualHeight((int) (child.getMinHeight() + rubberband));
     }
 
     private void cancelExpansion(final ExpandableView child) {
-        if (child.getContentHeight() == child.getMinHeight()) {
+        if (child.getActualHeight() == child.getMinHeight()) {
             mCallback.setUserLockedChild(child, false);
             return;
         }
-        ObjectAnimator anim = ObjectAnimator.ofInt(child, "contentHeight",
-                child.getContentHeight(), child.getMinHeight());
+        ObjectAnimator anim = ObjectAnimator.ofInt(child, "actualHeight",
+                child.getActualHeight(), child.getMinHeight());
         anim.setInterpolator(mInterpolator);
         anim.setDuration(SPRING_BACK_ANIMATION_LENGTH_MS);
         anim.addListener(new AnimatorListenerAdapter() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 27401ab..fbd6477 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -16,9 +16,7 @@
 
 package com.android.systemui.statusbar;
 
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator;
+import android.app.Notification;
 import android.content.Context;
 import android.graphics.drawable.AnimatedVectorDrawable;
 import android.graphics.drawable.AnimationDrawable;
@@ -39,6 +37,7 @@
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
 import com.android.systemui.statusbar.phone.PhoneStatusBar;
 import com.android.systemui.statusbar.stack.NotificationChildrenContainer;
+import com.android.systemui.statusbar.notification.NotificationHeaderView;
 import com.android.systemui.statusbar.stack.StackScrollState;
 import com.android.systemui.statusbar.stack.StackStateAnimator;
 import com.android.systemui.statusbar.stack.StackViewState;
@@ -90,32 +89,21 @@
     private StatusBarNotification mStatusBarNotification;
     private boolean mIsHeadsUp;
     private boolean mLastChronometerRunning = true;
-    private View mExpandButton;
-    private View mExpandButtonDivider;
-    private ViewStub mExpandButtonStub;
+    private NotificationHeaderView mNotificationHeader;
+    private ViewStub mNotificationHeaderStub;
     private ViewStub mChildrenContainerStub;
     private NotificationGroupManager mGroupManager;
-    private View mExpandButtonContainer;
     private boolean mChildrenExpanded;
     private boolean mIsSummaryWithChildren;
     private NotificationChildrenContainer mChildrenContainer;
-    private ValueAnimator mChildExpandAnimator;
-    private float mChildrenExpandProgress;
-    private float mExpandButtonStart;
     private ViewStub mGutsStub;
-    private boolean mHasExpandAction;
+    private boolean mHasNotificationHeader;
     private boolean mIsSystemChildExpanded;
     private boolean mIsPinned;
-    private OnClickListener mExpandClickListener = new OnClickListener() {
-        @Override
-        public void onClick(View v) {
-            mGroupManager.setGroupExpanded(mStatusBarNotification,
-                    !mChildrenExpanded);
-        }
-    };
     private FalsingManager mFalsingManager;
 
     private boolean mJustClicked;
+    private NotificationData.Entry mEntry;
     private boolean mChildInGroup;
 
     public NotificationContentView getPrivateLayout() {
@@ -173,10 +161,9 @@
         }
     }
 
-    public void setStatusBarNotification(StatusBarNotification statusBarNotification) {
+    private void setStatusBarNotification(StatusBarNotification statusBarNotification) {
         mStatusBarNotification = statusBarNotification;
         updateVetoButton();
-        updateExpandButton();
         onChildrenCountChanged();
     }
 
@@ -254,6 +241,13 @@
         return mChildrenContainer == null ? null : mChildrenContainer.getNotificationChildren();
     }
 
+    public int getNumberOfNotificationChildren() {
+        if (mChildrenContainer == null) {
+            return 0;
+        }
+        return mChildrenContainer.getNotificationChildren().size();
+    }
+
     /**
      * Apply the order given in the list to the children.
      *
@@ -304,15 +298,6 @@
         return mGuts;
     }
 
-    protected int calculateContentHeightFromActualHeight(int actualHeight) {
-        int realActualHeight = actualHeight;
-        if (hasBottomDecor()) {
-            realActualHeight -= getBottomDecorHeight();
-        }
-        realActualHeight = Math.max(getMinHeight(), realActualHeight);
-        return realActualHeight;
-    }
-
     /**
      * Set this notification to be pinned to the top if {@link #isHeadsUp()} is true. By doing this
      * the notification will be rendered on top of the screen.
@@ -382,6 +367,11 @@
         }
     }
 
+    public void setEntry(NotificationData.Entry entry) {
+        mEntry = entry;
+        setStatusBarNotification(entry.notification);
+    }
+
     public interface ExpansionLogger {
         public void logNotificationExpansion(String key, boolean userAction, boolean expanded);
     }
@@ -445,15 +435,13 @@
                 mGutsStub = null;
             }
         });
-        mExpandButtonStub = (ViewStub) findViewById(R.id.more_button_stub);
-        mExpandButtonStub.setOnInflateListener(new ViewStub.OnInflateListener() {
-
+        mNotificationHeaderStub = (ViewStub) findViewById(R.id.notification_header_stub);
+        mNotificationHeaderStub.setOnInflateListener(new ViewStub.OnInflateListener() {
             @Override
             public void onInflate(ViewStub stub, View inflated) {
-                mExpandButtonContainer = inflated;
-                mExpandButton = inflated.findViewById(R.id.notification_expand_button);
-                mExpandButtonDivider = inflated.findViewById(R.id.notification_expand_divider);
-                mExpandButtonContainer.setOnClickListener(mExpandClickListener);
+                mNotificationHeader = (NotificationHeaderView) inflated;
+                mNotificationHeader.setGroupManager(mGroupManager);
+                mNotificationHeader.bind(mEntry);
             }
         });
         mChildrenContainerStub = (ViewStub) findViewById(R.id.child_container_stub);
@@ -462,8 +450,6 @@
             @Override
             public void onInflate(ViewStub stub, View inflated) {
                 mChildrenContainer = (NotificationChildrenContainer) inflated;
-                mChildrenContainer.setCollapseClickListener(mExpandClickListener);
-                updateChildrenVisibility(false);
             }
         });
         mVetoButton = findViewById(R.id.veto);
@@ -479,48 +465,8 @@
         if (mChildrenContainer == null) {
             return;
         }
-        if (mChildExpandAnimator != null) {
-            mChildExpandAnimator.cancel();
-        }
-        float targetProgress = mChildrenExpanded ? 1.0f : 0.0f;
-        if (animated) {
-            if (mChildrenExpanded) {
-                mChildrenContainer.setVisibility(VISIBLE);
-            }
-            mExpandButtonStart = mExpandButtonContainer.getTranslationY();
-            mChildExpandAnimator = ValueAnimator.ofFloat(mChildrenExpandProgress, targetProgress);
-            mChildExpandAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
-                @Override
-                public void onAnimationUpdate(ValueAnimator animation) {
-                    setChildrenExpandProgress((float) animation.getAnimatedValue());
-                }
-            });
-            mChildExpandAnimator.addListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationEnd(Animator animation) {
-                    mChildExpandAnimator = null;
-                    if (!mChildrenExpanded) {
-                        mChildrenContainer.setVisibility(INVISIBLE);
-                    }
-                }
-            });
-            mChildExpandAnimator.setInterpolator(mLinearInterpolator);
-            mChildExpandAnimator.setDuration(
-                    StackStateAnimator.ANIMATION_DURATION_EXPAND_CLICKED);
-            mChildExpandAnimator.start();
-        } else {
-            setChildrenExpandProgress(targetProgress);
-            mChildrenContainer.setVisibility(mChildrenExpanded ? VISIBLE : INVISIBLE);
-        }
-    }
-
-    private void setChildrenExpandProgress(float progress) {
-        mChildrenExpandProgress = progress;
-        updateExpandButtonAppearance();
-        NotificationContentView showingLayout = getShowingLayout();
-        float alpha = 1.0f - mChildrenExpandProgress;
-        alpha = PhoneStatusBar.ALPHA_OUT.getInterpolation(alpha);
-        showingLayout.setAlpha(alpha);
+        mChildrenContainer.setVisibility(mIsSummaryWithChildren ? VISIBLE : INVISIBLE);
+        mPrivateLayout.setVisibility(!mIsSummaryWithChildren ? VISIBLE : INVISIBLE);
     }
 
     @Override
@@ -645,9 +591,9 @@
     public void applyExpansionToLayout() {
         boolean expand = isExpanded();
         if (expand && mExpandable) {
-            setContentHeight(mMaxExpandHeight);
+            setActualHeight(mMaxExpandHeight);
         } else {
-            setContentHeight(mRowMinHeight);
+            setActualHeight(mRowMinHeight);
         }
     }
 
@@ -673,18 +619,18 @@
         } else {
             maxContentHeight = getMaxExpandHeight();
         }
-        return maxContentHeight + getBottomDecorHeight();
+        return maxContentHeight;
     }
 
-    @Override
-    protected boolean hasBottomDecor() {
-        return BaseStatusBar.ENABLE_CHILD_NOTIFICATIONS
-                && !mIsHeadsUp && mGroupManager.hasGroupChildren(mStatusBarNotification);
+    private boolean isGroupExpanded() {
+        return mGroupManager.isGroupExpanded(mStatusBarNotification);
     }
 
-    @Override
-    protected boolean canHaveBottomDecor() {
-        return BaseStatusBar.ENABLE_CHILD_NOTIFICATIONS && !mIsHeadsUp;
+    /**
+     * @return whether this view has a header on the top of the content
+     */
+    private boolean hasNotificationHeader() {
+        return mIsSummaryWithChildren;
     }
 
     private void onChildrenCountChanged() {
@@ -693,6 +639,7 @@
         if (mIsSummaryWithChildren && mChildrenContainer == null) {
             mChildrenContainerStub.inflate();
         }
+        updateNotificationHeader();
         updateChildrenVisibility(true);
     }
 
@@ -812,105 +759,25 @@
 
     public void setChildrenExpanded(boolean expanded, boolean animate) {
         mChildrenExpanded = expanded;
-        updateChildrenVisibility(animate);
     }
 
-    public void updateExpandButton() {
-        boolean hasExpand = hasBottomDecor();
-        if (hasExpand != mHasExpandAction) {
-            if (hasExpand) {
-                if (mExpandButtonContainer == null) {
-                    mExpandButtonStub.inflate();
+    public void updateNotificationHeader() {
+        boolean hasHeader = hasNotificationHeader();
+        if (hasHeader != mHasNotificationHeader) {
+            if (hasHeader) {
+                if (mNotificationHeader == null) {
+                    mNotificationHeaderStub.inflate();
                 }
-                mExpandButtonContainer.setVisibility(View.VISIBLE);
-                updateExpandButtonAppearance();
-                updateExpandButtonColor();
-            } else if (mExpandButtonContainer != null) {
-                mExpandButtonContainer.setVisibility(View.GONE);
+                mNotificationHeader.setVisibility(View.VISIBLE);
+            } else if (mNotificationHeader != null) {
+                mNotificationHeader.setVisibility(View.GONE);
             }
             notifyHeightChanged(true  /* needsAnimation */);
         }
-        mHasExpandAction = hasExpand;
-    }
-
-    private void updateExpandButtonAppearance() {
-        if (mExpandButtonContainer == null) {
-            return;
+        if (hasHeader) {
+            mNotificationHeader.bind(mEntry);
         }
-        float expandButtonAlpha = 0.0f;
-        float expandButtonTranslation = 0.0f;
-        float containerTranslation = 0.0f;
-        int minHeight = getMinHeight();
-        if (!mChildrenExpanded || mChildExpandAnimator != null) {
-            int expandActionHeight = getBottomDecorHeight();
-            int translationY = getActualHeight() - expandActionHeight;
-            if (translationY > minHeight) {
-                containerTranslation = translationY;
-                expandButtonAlpha = 1.0f;
-                expandButtonTranslation = 0.0f;
-            } else {
-                containerTranslation = minHeight;
-                float progress = expandActionHeight != 0
-                        ? (minHeight - translationY) / (float) expandActionHeight
-                        : 1.0f;
-                expandButtonTranslation = -progress * expandActionHeight * 0.7f;
-                float alphaProgress = Math.min(progress / 0.7f, 1.0f);
-                alphaProgress = PhoneStatusBar.ALPHA_OUT.getInterpolation(alphaProgress);
-                expandButtonAlpha = 1.0f - alphaProgress;
-            }
-        }
-        if (mChildExpandAnimator != null || mChildrenExpanded) {
-            expandButtonAlpha = (1.0f - mChildrenExpandProgress)
-                    * expandButtonAlpha;
-            expandButtonTranslation = (1.0f - mChildrenExpandProgress)
-                    * expandButtonTranslation;
-            float newTranslation = -getBottomDecorHeight();
-
-            // We don't want to take the actual height of the view as this is already
-            // interpolated by a custom interpolator leading to a confusing animation. We want
-            // to have a stable end value to interpolate in between
-            float collapsedHeight = !mChildrenExpanded
-                    ? Math.max(StackStateAnimator.getFinalActualHeight(this)
-                            - getBottomDecorHeight(), minHeight)
-                    : mExpandButtonStart;
-            float translationProgress = mFastOutSlowInInterpolator.getInterpolation(
-                    mChildrenExpandProgress);
-            containerTranslation = (1.0f - translationProgress) * collapsedHeight
-                    + translationProgress * newTranslation;
-        }
-        mExpandButton.setAlpha(expandButtonAlpha);
-        mExpandButtonDivider.setAlpha(expandButtonAlpha);
-        mExpandButton.setTranslationY(expandButtonTranslation);
-        mExpandButtonContainer.setTranslationY(containerTranslation);
-        NotificationContentView showingLayout = getShowingLayout();
-        float layoutTranslation =
-                mExpandButtonContainer.getTranslationY() - showingLayout.getContentHeight();
-        layoutTranslation = Math.min(layoutTranslation, 0);
-        if (!mChildrenExpanded && mChildExpandAnimator == null) {
-            // Needed for the DragDownHelper in order not to jump there, as the position
-            // can be negative for a short time.
-            layoutTranslation = 0;
-        }
-        showingLayout.setTranslationY(layoutTranslation);
-        if (mChildrenContainer != null) {
-            mChildrenContainer.setTranslationY(
-                    mExpandButtonContainer.getTranslationY() + getBottomDecorHeight());
-        }
-    }
-
-    private void updateExpandButtonColor() {
-        // TODO: This needs some more baking, currently only the divider is colored according to
-        // the tint, but legacy black doesn't work yet perfectly for the button etc.
-        int color = getRippleColor();
-        if (color == mNormalRippleColor) {
-            color = 0;
-        }
-        if (mExpandButtonDivider != null) {
-            applyTint(mExpandButtonDivider, color);
-        }
-        if (mChildrenContainer != null) {
-            mChildrenContainer.setTintColor(color);
-        }
+        mHasNotificationHeader = hasHeader;
     }
 
     public static void applyTint(View v, int color) {
@@ -947,14 +814,13 @@
     @Override
     public void setActualHeight(int height, boolean notifyListeners) {
         super.setActualHeight(height, notifyListeners);
-        int contentHeight = calculateContentHeightFromActualHeight(height);
+        int contentHeight = Math.max(getMinHeight(), height);
         mPrivateLayout.setContentHeight(contentHeight);
         mPublicLayout.setContentHeight(contentHeight);
         if (mGuts != null) {
             mGuts.setActualHeight(height);
         }
         invalidate();
-        updateExpandButtonAppearance();
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
index 2652319..af59ac7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
@@ -33,7 +33,6 @@
  */
 public abstract class ExpandableView extends FrameLayout {
 
-    private final int mBottomDecorHeight;
     protected OnHeightChangedListener mOnHeightChangedListener;
     protected int mMaxViewHeight;
     private int mActualHeight;
@@ -50,12 +49,6 @@
         super(context, attrs);
         mMaxViewHeight = getResources().getDimensionPixelSize(
                 R.dimen.notification_max_height);
-        mBottomDecorHeight = resolveBottomDecorHeight();
-    }
-
-    protected int resolveBottomDecorHeight() {
-        return getResources().getDimensionPixelSize(
-                R.dimen.notification_bottom_decor_height);
     }
 
     @Override
@@ -103,10 +96,6 @@
         }
         mMatchParentViews.clear();
         int width = MeasureSpec.getSize(widthMeasureSpec);
-        if (canHaveBottomDecor()) {
-            // We always account for the expandAction as well.
-            ownHeight += mBottomDecorHeight;
-        }
         setMeasuredDimension(width, ownHeight);
     }
 
@@ -120,7 +109,7 @@
         if (!mActualHeightInitialized && mActualHeight == 0) {
             int initialHeight = getInitialHeight();
             if (initialHeight != 0) {
-                setContentHeight(initialHeight);
+                setActualHeight(initialHeight);
             }
         }
         updateClipping();
@@ -178,8 +167,8 @@
         }
     }
 
-    public void setContentHeight(int contentHeight) {
-        setActualHeight(contentHeight + getBottomDecorHeight(), true);
+    public void setActualHeight(int actualHeight) {
+        setActualHeight(actualHeight, true /* notifyListeners */);
     }
 
     /**
@@ -192,31 +181,6 @@
     }
 
     /**
-     * This view may have a bottom decor which will be placed below the content. If it has one, this
-     * view will be layouted higher than just the content by {@link #mBottomDecorHeight}.
-     * @return the height of the decor if it currently has one
-     */
-    public int getBottomDecorHeight() {
-        return hasBottomDecor() ? mBottomDecorHeight : 0;
-    }
-
-    /**
-     * @return whether this view may have a bottom decor at all. This will force the view to layout
-     *         itself higher than just it's content
-     */
-    protected boolean canHaveBottomDecor() {
-        return false;
-    }
-
-    /**
-     * @return whether this view has a decor view below it's content. This will make the intrinsic
-     *         height from {@link #getIntrinsicHeight()} higher as well
-     */
-    protected boolean hasBottomDecor() {
-        return false;
-    }
-
-    /**
      * @return The maximum height of this notification.
      */
     public int getMaxContentHeight() {
@@ -363,10 +327,6 @@
         outRect.top += getClipTopOptimization();
     }
 
-    public int getContentHeight() {
-        return mActualHeight - getBottomDecorHeight();
-    }
-
     public boolean isSummaryWithChildren() {
         return false;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java
index 9653b67..8e8ce1a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java
@@ -70,13 +70,4 @@
     public NotificationOverflowIconsView getIconsView() {
         return mIconsView;
     }
-
-    protected int getContentHeightFromActualHeight(int actualHeight) {
-        int realActualHeight = actualHeight;
-        if (hasBottomDecor()) {
-            realActualHeight -= getBottomDecorHeight();
-        }
-        realActualHeight = Math.max(getMinHeight(), realActualHeight);
-        return realActualHeight;
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderView.java
new file mode 100644
index 0000000..ec26cc4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderView.java
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2015 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.notification;
+
+import android.annotation.Nullable;
+import android.app.Notification;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.graphics.drawable.Drawable;
+import android.service.notification.StatusBarNotification;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.FrameLayout;
+import android.widget.ImageButton;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.android.internal.util.NotificationColorUtil;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.BaseStatusBar;
+import com.android.systemui.statusbar.ExpandableNotificationRow;
+import com.android.systemui.statusbar.NotificationData;
+import com.android.systemui.statusbar.phone.NotificationGroupManager;
+
+import java.util.List;
+
+/**
+ * A header for a notification view
+ */
+public class NotificationHeaderView extends FrameLayout {
+
+    private static final int DEFAULT_ICON_TINT_COLOR = 0xff616161;
+    private final NotificationColorUtil mNotificationColorUtil;
+    private NotificationData.Entry mNotificationEntry;
+    private ImageView mIconView;
+    private TextView mAppName;
+    private TextView mPostTime;
+    private TextView mChildCount;
+    private TextView mSubTextDivider;
+    private TextView mSubText;
+    private NotificationGroupManager mGroupManager;
+    private ImageButton mExpandButton;
+
+    public NotificationHeaderView(Context context) {
+        this(context, null);
+    }
+
+    public NotificationHeaderView(Context context, @Nullable AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public NotificationHeaderView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+        this(context, attrs, defStyleAttr, 0);
+    }
+
+    public NotificationHeaderView(Context context, @Nullable AttributeSet attrs, int defStyleAttr,
+            int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+        mNotificationColorUtil = NotificationColorUtil.getInstance(context);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mIconView = (ImageView) findViewById(R.id.header_notification_icon);
+        mAppName = (TextView) findViewById(R.id.app_name_text);
+        mSubTextDivider = (TextView) findViewById(R.id.app_title_sub_text_divider);
+        mSubText = (TextView) findViewById(R.id.title_sub_text);
+        mPostTime = (TextView) findViewById(R.id.post_time);
+        mChildCount = (TextView) findViewById(R.id.number_of_children);
+        mExpandButton = (ImageButton) findViewById(R.id.notification_expand_button);
+        mExpandButton.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                mGroupManager.toggleGroupExpansion(mNotificationEntry.notification);
+            }
+        });
+    }
+
+    public void bind(NotificationData.Entry notificationEntry) {
+        mNotificationEntry = notificationEntry;
+        StatusBarNotification sbn = notificationEntry.notification;
+        int notificationColor = getNotificationColor(sbn);
+        bindIcon(notificationColor);
+        bindNumber(notificationColor);
+        bindAppName(sbn);
+        bindSubText();
+        bindTime(sbn);
+        bindExpandButton(sbn);
+    }
+
+    private void bindExpandButton(StatusBarNotification sbn) {
+        boolean summaryOfGroup = mGroupManager.isSummaryOfGroup(sbn);
+        mExpandButton.setVisibility(summaryOfGroup ? VISIBLE : GONE);
+    }
+
+    private void bindSubText() {
+        List<ExpandableNotificationRow> notificationChildren =
+                mNotificationEntry.row.getNotificationChildren();
+        CharSequence subText = null;
+        if (notificationChildren != null) {
+            for (int i = 0; i < notificationChildren.size(); i++) {
+                ExpandableNotificationRow row = notificationChildren.get(i);
+                CharSequence rowSubText = row.getSubText();
+                if (TextUtils.isEmpty(rowSubText)
+                        || (subText != null && !subText.equals(rowSubText))) {
+                    // The children don't have a common subText
+                    subText = null;
+                    break;
+                } else if (subText == null) {
+                    subText = rowSubText;
+                }
+            }
+        };
+        setSubText(subText);
+    }
+
+    private void setSubText(CharSequence subText) {
+        boolean goneInHeader = TextUtils.isEmpty(subText);
+        if (goneInHeader) {
+            mSubText.setVisibility(GONE);
+            mSubTextDivider.setVisibility(GONE);
+        } else {
+            mSubText.setVisibility(VISIBLE);
+            mSubText.setText(subText);
+            mSubTextDivider.setVisibility(VISIBLE);
+        }
+        List<ExpandableNotificationRow> notificationChildren =
+                mNotificationEntry.row.getNotificationChildren();
+        if (notificationChildren != null) {
+            for (int i = 0; i < notificationChildren.size(); i++) {
+                ExpandableNotificationRow row = notificationChildren.get(i);
+                row.setContentSubTextVisible(goneInHeader);
+            }
+        }
+    }
+
+    private int getNotificationColor(StatusBarNotification sbn) {
+        int color = sbn.getNotification().color;
+        if (color == Notification.COLOR_DEFAULT) {
+            return DEFAULT_ICON_TINT_COLOR;
+        }
+        return color;
+    }
+
+    private void bindNumber(int notificationColor) {
+        int numberOfNotificationChildren = mNotificationEntry.row.getNumberOfNotificationChildren();
+        boolean visible = numberOfNotificationChildren > 0;
+        if (visible) {
+            mChildCount.setText("(" + numberOfNotificationChildren + ")");
+            mChildCount.setTextColor(notificationColor);
+            mChildCount.setVisibility(VISIBLE);
+        } else {
+            mChildCount.setVisibility(GONE);
+        }
+    }
+
+    private void bindTime(StatusBarNotification sbn) {
+
+    }
+
+    private void bindIcon(int notificationColor) {
+        Drawable icon = mNotificationEntry.icon.getDrawable().getConstantState()
+                .newDrawable(getResources()).mutate();
+        mIconView.setImageDrawable(icon);
+        if (NotificationUtils.isGrayscale(mIconView, mNotificationColorUtil)) {
+            icon.setTint(notificationColor);
+        }
+    }
+
+    private void bindAppName(StatusBarNotification sbn) {
+        PackageManager pmUser = BaseStatusBar.getPackageManagerForUser(getContext(),
+                sbn.getUser().getIdentifier());
+        final String pkg = sbn.getPackageName();
+        String appname = pkg;
+        try {
+            final ApplicationInfo info = pmUser.getApplicationInfo(pkg,
+                    PackageManager.GET_UNINSTALLED_PACKAGES
+                            | PackageManager.GET_DISABLED_COMPONENTS);
+            if (info != null) {
+                appname = String.valueOf(pmUser.getApplicationLabel(info));
+
+            }
+        } catch (PackageManager.NameNotFoundException e) {
+            // app is gone, just show package name
+        }
+        mAppName.setText(appname);
+    }
+
+    public void setGroupManager(NotificationGroupManager groupManager) {
+        mGroupManager = groupManager;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java
new file mode 100644
index 0000000..c931800
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2015 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.notification;
+
+import android.view.View;
+import android.widget.ImageView;
+
+import com.android.internal.util.NotificationColorUtil;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.StatusBarIconView;
+
+/**
+ * A util class for various reusable functions
+ */
+public class NotificationUtils {
+    public static boolean isGrayscale(ImageView v, NotificationColorUtil colorUtil) {
+        Object isGrayscale = v.getTag(R.id.icon_is_grayscale);
+        if (isGrayscale != null) {
+            return Boolean.TRUE.equals(isGrayscale);
+        }
+        boolean grayscale = colorUtil.isGrayscaleIcon(v.getDrawable());
+        v.setTag(R.id.icon_is_grayscale, grayscale);
+        return grayscale;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
index bf107ce..d0b3c4b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
@@ -106,7 +106,7 @@
                         }
                     });
                 } else {
-                    group.summary.row.updateExpandButton();
+                    group.summary.row.updateNotificationHeader();
                 }
             }
         }
@@ -130,7 +130,7 @@
         } else {
             group.children.add(added);
             if (group.summary != null && group.children.size() == 1 && !group.expanded) {
-                group.summary.row.updateExpandButton();
+                group.summary.row.updateNotificationHeader();
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
index 5de1c13..d5b980e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
@@ -42,6 +42,7 @@
 import com.android.systemui.statusbar.NotificationData;
 import com.android.systemui.statusbar.SignalClusterView;
 import com.android.systemui.statusbar.StatusBarIconView;
+import com.android.systemui.statusbar.notification.NotificationUtils;
 import com.android.systemui.tuner.TunerService;
 import com.android.systemui.tuner.TunerService.Tunable;
 
@@ -401,23 +402,13 @@
         for (int i = 0; i < mNotificationIcons.getChildCount(); i++) {
             StatusBarIconView v = (StatusBarIconView) mNotificationIcons.getChildAt(i);
             boolean isPreL = Boolean.TRUE.equals(v.getTag(R.id.icon_is_pre_L));
-            boolean colorize = !isPreL || isGrayscale(v);
+            boolean colorize = !isPreL || NotificationUtils.isGrayscale(v, mNotificationColorUtil);
             if (colorize) {
                 v.setImageTintList(ColorStateList.valueOf(mIconTint));
             }
         }
     }
 
-    private boolean isGrayscale(StatusBarIconView v) {
-        Object isGrayscale = v.getTag(R.id.icon_is_grayscale);
-        if (isGrayscale != null) {
-            return Boolean.TRUE.equals(isGrayscale);
-        }
-        boolean grayscale = mNotificationColorUtil.isGrayscaleIcon(v.getDrawable());
-        v.setTag(R.id.icon_is_grayscale, grayscale);
-        return grayscale;
-    }
-
     public void appTransitionPending() {
         mTransitionPending = true;
     }
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 3c9e8cf..da82456 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
@@ -21,7 +21,6 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
-import android.widget.Button;
 
 import com.android.systemui.R;
 import com.android.systemui.statusbar.ExpandableNotificationRow;
@@ -40,10 +39,9 @@
     private final int mMaxNotificationHeight;
     private final List<View> mDividers = new ArrayList<>();
     private final List<ExpandableNotificationRow> mChildren = new ArrayList<>();
-    private final View mCollapseButton;
-    private final View mCollapseDivider;
-    private final int mCollapseButtonHeight;
+    private final int mNotificationHeaderHeight;
     private final int mNotificationAppearDistance;
+    private final float mHeaderTopPaddingSubstraction;
 
     public NotificationChildrenContainer(Context context) {
         this(context, null);
@@ -68,14 +66,9 @@
                 R.dimen.notification_max_height);
         mNotificationAppearDistance = getResources().getDimensionPixelSize(
                 R.dimen.notification_appear_distance);
-        LayoutInflater inflater = mContext.getSystemService(LayoutInflater.class);
-        mCollapseButton = inflater.inflate(R.layout.notification_collapse_button, this,
-                false);
-        mCollapseButtonHeight = getResources().getDimensionPixelSize(
-                R.dimen.notification_bottom_decor_height);
-        addView(mCollapseButton);
-        mCollapseDivider = inflateDivider();
-        addView(mCollapseDivider);
+        mNotificationHeaderHeight = getResources().getDimensionPixelSize(
+                R.dimen.notification_header_height);
+        mHeaderTopPaddingSubstraction = 2 * getResources().getDisplayMetrics().density;
     }
 
     @Override
@@ -103,9 +96,6 @@
                 firstChild = false;
             }
         }
-        mCollapseButton.layout(0, 0, getWidth(), mCollapseButtonHeight);
-        mCollapseDivider.layout(0, mCollapseButtonHeight - mDividerHeight, getWidth(),
-                mCollapseButtonHeight);
     }
 
     @Override
@@ -120,11 +110,7 @@
         }
         int newHeightSpec = MeasureSpec.makeMeasureSpec(ownMaxHeight, MeasureSpec.AT_MOST);
         int dividerHeightSpec = MeasureSpec.makeMeasureSpec(mDividerHeight, MeasureSpec.EXACTLY);
-        int collapseButtonHeightSpec = MeasureSpec.makeMeasureSpec(mCollapseButtonHeight,
-                MeasureSpec.EXACTLY);
-        mCollapseButton.measure(widthMeasureSpec, collapseButtonHeightSpec);
-        mCollapseDivider.measure(widthMeasureSpec, dividerHeightSpec);
-        int height = mCollapseButtonHeight;
+        int height = mNotificationHeaderHeight;
         int childCount = mChildren.size();
         boolean firstChild = true;
         for (int i = 0; i < childCount; i++) {
@@ -247,7 +233,7 @@
      */
     public void getState(StackScrollState resultState, StackViewState parentState) {
         int childCount = mChildren.size();
-        int yPosition = mCollapseButtonHeight;
+        int yPosition = mNotificationHeaderHeight;
         boolean firstChild = true;
         for (int i = 0; i < childCount; i++) {
             ExpandableNotificationRow child = mChildren.get(i);
@@ -302,10 +288,6 @@
         }
     }
 
-    public void setCollapseClickListener(OnClickListener collapseClickListener) {
-        mCollapseButton.setOnClickListener(collapseClickListener);
-    }
-
     /**
      * This is called when the children expansion has changed and positions the children properly
      * for an appear animation.
@@ -376,13 +358,6 @@
             stateAnimator.startStackAnimations(child, viewState, state, -1, delay);
             notGoneIndex++;
         }
-        dividerState.initFrom(mCollapseButton);
-        dividerState.alpha = 1.0f;
-        stateAnimator.startViewAnimations(mCollapseButton, dividerState, baseDelay, duration);
-        dividerState.initFrom(mCollapseDivider);
-        dividerState.alpha = 1.0f;
-        dividerState.yTranslation = 0.0f;
-        stateAnimator.startViewAnimations(mCollapseDivider, dividerState, baseDelay, duration);
     }
 
     public ExpandableNotificationRow getViewAtPosition(float y) {
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 d50f8ac5..1b66073 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -2788,16 +2788,6 @@
         return touchY > mTopPadding + mStackTranslation;
     }
 
-    private void updateExpandButtons() {
-        for (int i = 0; i < getChildCount(); i++) {
-            View child = getChildAt(i);
-            if (child instanceof ExpandableNotificationRow) {
-                ExpandableNotificationRow row = (ExpandableNotificationRow) child;
-                row.updateExpandButton();
-            }
-        }
-    }
-
     @Override
     public void onGroupExpansionChanged(ExpandableNotificationRow changedRow, boolean expanded) {
         boolean animated = mAnimationsEnabled && mIsExpanded;
@@ -2811,7 +2801,6 @@
 
     @Override
     public void onGroupsProhibitedChanged() {
-        updateExpandButtons();
     }
 
     @Override