Merge "Correct how to deal with print service installation" into nyc-dev
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 2c34371..d8f0ac5 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -2994,7 +2994,6 @@
             contentView.setViewVisibility(R.id.chronometer, View.GONE);
             contentView.setViewVisibility(R.id.header_sub_text, View.GONE);
             contentView.setViewVisibility(R.id.header_content_info, View.GONE);
-            contentView.setViewVisibility(R.id.number_of_children, View.GONE);
             contentView.setViewVisibility(R.id.sub_text_divider, View.GONE);
             contentView.setViewVisibility(R.id.content_info_divider, View.GONE);
             contentView.setViewVisibility(R.id.time_divider, View.GONE);
@@ -3095,7 +3094,6 @@
 
         private void bindNotificationHeader(RemoteViews contentView) {
             bindSmallIcon(contentView);
-            bindChildCountColor(contentView);
             bindHeaderAppName(contentView);
             bindHeaderSubText(contentView);
             bindContentInfo(contentView);
@@ -3104,10 +3102,6 @@
             bindProfileBadge(contentView);
         }
 
-        private void bindChildCountColor(RemoteViews contentView) {
-            contentView.setTextColor(R.id.number_of_children, resolveColor());
-        }
-
         private void bindContentInfo(RemoteViews contentView) {
             boolean visible = false;
             if (mN.extras.getCharSequence(EXTRA_INFO_TEXT) != null) {
diff --git a/core/java/android/view/NotificationHeaderView.java b/core/java/android/view/NotificationHeaderView.java
index b9a7421..cff9d8e 100644
--- a/core/java/android/view/NotificationHeaderView.java
+++ b/core/java/android/view/NotificationHeaderView.java
@@ -35,7 +35,6 @@
 public class NotificationHeaderView extends ViewGroup {
     public static final int NO_COLOR = -1;
     private final int mChildMinWidth;
-    private final int mExpandTopPadding;
     private final int mContentEndMargin;
     private View mAppName;
     private View mSubTextView;
@@ -43,12 +42,10 @@
     private HeaderTouchListener mTouchListener = new HeaderTouchListener();
     private ImageView mExpandButton;
     private View mIcon;
-    private TextView mChildCount;
     private View mProfileBadge;
     private View mInfo;
     private int mIconColor;
     private int mOriginalNotificationColor;
-    private boolean mGroupHeader;
     private boolean mExpanded;
     private boolean mShowWorkBadgeAtEnd;
 
@@ -70,7 +67,6 @@
                 com.android.internal.R.dimen.notification_header_shrink_min_width);
         mContentEndMargin = getResources().getDimensionPixelSize(
                 com.android.internal.R.dimen.notification_content_margin_end);
-        mExpandTopPadding = (int) (1 * getResources().getDisplayMetrics().density);
     }
 
     @Override
@@ -80,7 +76,6 @@
         mSubTextView = findViewById(com.android.internal.R.id.header_sub_text);
         mExpandButton = (ImageView) findViewById(com.android.internal.R.id.expand_button);
         mIcon = findViewById(com.android.internal.R.id.icon);
-        mChildCount = (TextView) findViewById(com.android.internal.R.id.number_of_children);
         mProfileBadge = findViewById(com.android.internal.R.id.profile_badge);
         mInfo = findViewById(com.android.internal.R.id.header_content_info);
     }
@@ -193,17 +188,6 @@
         updateTouchListener();
     }
 
-    public void setChildCount(int childCount) {
-        if (childCount > 0) {
-            mChildCount.setText(getContext().getString(
-                    com.android.internal.R.string.notification_children_count_bracketed,
-                    childCount));
-            mChildCount.setVisibility(VISIBLE);
-        } else {
-            mChildCount.setVisibility(GONE);
-        }
-    }
-
     @RemotableViewMethod
     public void setOriginalIconColor(int color) {
         mIconColor = color;
@@ -222,11 +206,6 @@
         return mOriginalNotificationColor;
     }
 
-    public void setIsGroupHeader(boolean isGroupHeader) {
-        mGroupHeader = isGroupHeader;
-        updateExpandButton();
-    }
-
     @RemotableViewMethod
     public void setExpanded(boolean expanded) {
         mExpanded = expanded;
@@ -235,24 +214,13 @@
 
     private void updateExpandButton() {
         int drawableId;
-        int paddingTop = 0;
-        if (mGroupHeader) {
-            if (mExpanded) {
-                drawableId = com.android.internal.R.drawable.ic_collapse_bundle;
-            } else {
-                drawableId =com.android.internal.R.drawable.ic_expand_bundle;
-            }
+        if (mExpanded) {
+            drawableId = com.android.internal.R.drawable.ic_collapse_notification;
         } else {
-            if (mExpanded) {
-                drawableId = com.android.internal.R.drawable.ic_collapse_notification;
-            } else {
-                drawableId = com.android.internal.R.drawable.ic_expand_notification;
-            }
-            paddingTop = mExpandTopPadding;
+            drawableId = com.android.internal.R.drawable.ic_expand_notification;
         }
         mExpandButton.setImageDrawable(getContext().getDrawable(drawableId));
         mExpandButton.setColorFilter(mOriginalNotificationColor);
-        mExpandButton.setPadding(0, paddingTop, 0, 0);
     }
 
     public void setShowWorkBadgeAtEnd(boolean showWorkBadgeAtEnd) {
diff --git a/core/java/com/android/internal/widget/MediaNotificationView.java b/core/java/com/android/internal/widget/MediaNotificationView.java
index 6bba1b3..f63afad 100644
--- a/core/java/com/android/internal/widget/MediaNotificationView.java
+++ b/core/java/com/android/internal/widget/MediaNotificationView.java
@@ -89,36 +89,50 @@
         int topMargin = getMeasuredHeight() - mRightIcon.getMeasuredHeight()
                 - iconParams.bottomMargin;
         // If the topMargin is high enough we can also remove the header constraint!
+        boolean reMeasure = false;
         if (!hasIcon || topMargin >= mImageMinTopMargin) {
-            resetHeaderIndention();
+            reMeasure = resetHeaderIndention();
         } else {
             int paddingEnd = mNotificationContentImageMarginEnd;
             ViewGroup.MarginLayoutParams headerParams =
                     (MarginLayoutParams) mHeader.getLayoutParams();
-            headerParams.setMarginEnd(mRightIcon.getMeasuredWidth() + iconParams.getMarginEnd());
-            if (mHeader.getPaddingEnd() != paddingEnd) {
-                mHeader.setPadding(
-                        isLayoutRtl() ? paddingEnd : mHeader.getPaddingLeft(),
-                        mHeader.getPaddingTop(),
-                        isLayoutRtl() ? mHeader.getPaddingLeft() : paddingEnd,
-                        mHeader.getPaddingBottom());
+            int newMarginEnd = mRightIcon.getMeasuredWidth() + iconParams.getMarginEnd();
+            if (headerParams.getMarginEnd() != newMarginEnd) {
+                headerParams.setMarginEnd(newMarginEnd);
                 mHeader.setLayoutParams(headerParams);
+                reMeasure = true;
             }
+            if (mHeader.getPaddingEnd() != paddingEnd) {
+                mHeader.setPaddingRelative(mHeader.getPaddingStart(),
+                        mHeader.getPaddingTop(),
+                        paddingEnd,
+                        mHeader.getPaddingBottom());
+                reMeasure = true;
+            }
+        }
+        if (reMeasure) {
+            measureChildWithMargins(mHeader, widthMeasureSpec, 0, heightMeasureSpec, 0);
         }
     }
 
-    private void resetHeaderIndention() {
+    private boolean resetHeaderIndention() {
+        boolean remeasure = false;
         if (mHeader.getPaddingEnd() != mNotificationContentMarginEnd) {
-            ViewGroup.MarginLayoutParams headerParams =
-                    (MarginLayoutParams) mHeader.getLayoutParams();
-            headerParams.setMarginEnd(0);
-            mHeader.setPadding(
-                    isLayoutRtl() ? mNotificationContentMarginEnd : mHeader.getPaddingLeft(),
+            mHeader.setPaddingRelative(mHeader.getPaddingStart(),
                     mHeader.getPaddingTop(),
-                    isLayoutRtl() ? mHeader.getPaddingLeft() : mNotificationContentMarginEnd,
+                    mNotificationContentMarginEnd,
                     mHeader.getPaddingBottom());
-            mHeader.setLayoutParams(headerParams);
+            remeasure = true;
         }
+        ViewGroup.MarginLayoutParams headerParams =
+                (MarginLayoutParams) mHeader.getLayoutParams();
+        headerParams.setMarginEnd(0);
+        if (headerParams.getMarginEnd() != 0) {
+            headerParams.setMarginEnd(0);
+            mHeader.setLayoutParams(headerParams);
+            remeasure = true;
+        }
+        return remeasure;
     }
 
     public MediaNotificationView(Context context, AttributeSet attrs, int defStyleAttr,
diff --git a/core/res/res/layout/notification_template_header.xml b/core/res/res/layout/notification_template_header.xml
index 6669bae..b8b00bf 100644
--- a/core/res/res/layout/notification_template_header.xml
+++ b/core/res/res/layout/notification_template_header.xml
@@ -33,16 +33,6 @@
         android:layout_marginEnd="3dp"
         />
     <TextView
-        android:id="@+id/number_of_children"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:textAppearance="@style/TextAppearance.Material.Notification"
-        android:layout_marginEnd="3dp"
-        android:layout_marginStart="2dp"
-        android:visibility="gone"
-        android:singleLine="true"
-        />
-    <TextView
         android:id="@+id/app_name_text"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index d8efd63..5574857 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -548,9 +548,6 @@
          [CHAR LIMIT=4] -->
     <string name="status_bar_notification_info_overflow">999+</string>
 
-    <!-- The number of notifications in the notification header. An example would be (2) or (12) -->
-    <string name="notification_children_count_bracketed">(<xliff:g id="notificationCount" example="1">%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>
 
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 15521e4..e1f28cc 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2405,11 +2405,9 @@
   <java-symbol type="id" name="notification_material_reply_text_2" />
   <java-symbol type="id" name="notification_material_reply_text_3" />
 
-  <java-symbol type="string" name="notification_children_count_bracketed" />
   <java-symbol type="string" name="notification_hidden_text" />
   <java-symbol type="string" name="notification_hidden_by_policy_text" />
   <java-symbol type="id" name="app_name_text" />
-  <java-symbol type="id" name="number_of_children" />
   <java-symbol type="id" name="header_sub_text" />
   <java-symbol type="id" name="expand_button" />
   <java-symbol type="id" name="notification_header" />
diff --git a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
index c17be06..c56a12f 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
@@ -282,6 +282,24 @@
      * Launches an intent to view the specified document.
      */
     private void openDocument(DocumentInfo doc, Model model) {
+
+        // Provide specialized handling of downloaded APKs This sends the APK
+        // details off to get extra security information added, and finally
+        // to be handled by the package manager.
+        if (MimePredicate.isApkType(doc.mimeType)) {
+            // First try managing the document; we expect manager to filter
+            // based on authority, so we don't grant.
+            final Intent manage = new Intent(DocumentsContract.ACTION_MANAGE_DOCUMENT);
+            manage.setData(doc.derivedUri);
+
+            try {
+                startActivity(manage);
+                return;
+            } catch (ActivityNotFoundException ex) {
+                // fall back to regular handling below.
+            }
+        }
+
         Intent intent = new QuickViewIntentBuilder(
                 getPackageManager(), getResources(), doc, model).build();
 
@@ -296,7 +314,7 @@
             }
         }
 
-        // Fallback to traditional VIEW action...
+        // Fall back to traditional VIEW action...
         intent = new Intent(Intent.ACTION_VIEW);
         intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
         intent.setData(doc.derivedUri);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/MimePredicate.java b/packages/DocumentsUI/src/com/android/documentsui/MimePredicate.java
index 9df55a0..2f202e7 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/MimePredicate.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/MimePredicate.java
@@ -16,12 +16,15 @@
 
 package com.android.documentsui;
 
+import android.annotation.Nullable;
+
 import com.android.documentsui.model.DocumentInfo;
 import com.android.internal.util.Predicate;
 
 public class MimePredicate implements Predicate<DocumentInfo> {
     private final String[] mFilters;
 
+    private static final String APK_TYPE = "application/vnd.android.package-archive";
     /**
      * MIME types that are visual in nature. For example, they should always be
      * shown as thumbnails in list mode.
@@ -92,4 +95,8 @@
             return false;
         }
     }
+
+    public static boolean isApkType(@Nullable String mimeType) {
+        return APK_TYPE.equals(mimeType);
+    }
 }
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index b9eee2e..9697ea6 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -48,6 +48,7 @@
     <item type="id" name="transformation_start_y_tag"/>
     <item type="id" name="transformation_start_scale_x_tag"/>
     <item type="id" name="transformation_start_scale_y_tag"/>
+    <item type="id" name="custom_background_color"/>
 
     <!-- Whether the icon is from a notification for which targetSdk < L -->
     <item type="id" name="icon_is_pre_L"/>
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index 913b2b3..2e94bc7 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -23,7 +23,6 @@
 
 import com.android.internal.widget.LockPatternUtils;
 import com.android.keyguard.ViewMediatorCallback;
-import com.android.systemui.shortcut.ShortcutKeyDispatcher;
 import com.android.systemui.statusbar.ScrimView;
 import com.android.systemui.statusbar.phone.KeyguardBouncer;
 import com.android.systemui.statusbar.phone.ScrimController;
@@ -72,8 +71,8 @@
     }
 
     public ScrimController createScrimController(ScrimView scrimBehind, ScrimView scrimInFront,
-            View headsUpScrim, boolean scrimSrcEnabled) {
-        return new ScrimController(scrimBehind, scrimInFront, headsUpScrim, scrimSrcEnabled);
+            View headsUpScrim) {
+        return new ScrimController(scrimBehind, scrimInFront, headsUpScrim);
     }
 
     public <T> T createInstance(Class<T> classType) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index effe581..5652c7d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -36,7 +36,9 @@
 import com.android.systemui.R;
 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.NotificationStackScrollLayout;
+import com.android.systemui.statusbar.stack.StackStateAnimator;
 
 /**
  * Base class for both {@link ExpandableNotificationRow} and {@link NotificationOverflowContainer}
@@ -121,6 +123,7 @@
     private float mAnimationTranslationY;
     private boolean mDrawingAppearAnimation;
     private ValueAnimator mAppearAnimator;
+    private ValueAnimator mBackgroundColorAnimator;
     private float mAppearAnimationFraction = -1.0f;
     private float mAppearAnimationTranslation;
     private boolean mShowingLegacyBackground;
@@ -157,6 +160,9 @@
     };
     private float mShadowAlpha = 1.0f;
     private FakeShadowView mFakeShadow;
+    private int mCurrentBackgroundTint;
+    private int mTargetTint;
+    private int mStartTint;
 
     public ActivatableNotificationView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -457,21 +463,63 @@
      * Sets the tint color of the background
      */
     public void setTintColor(int color) {
+        setTintColor(color, false);
+    }
+
+    /**
+     * Sets the tint color of the background
+     */
+    public void setTintColor(int color, boolean animated) {
         mBgTint = color;
-        updateBackgroundTint();
+        updateBackgroundTint(animated);
     }
 
     protected void updateBackgroundTint() {
-        int color = getBgColor();
+        updateBackgroundTint(false /* animated */);
+    }
+
+    private void updateBackgroundTint(boolean animated) {
+        if (mBackgroundColorAnimator != null) {
+            mBackgroundColorAnimator.cancel();
+        }
         int rippleColor = getRippleColor();
+        mBackgroundDimmed.setRippleColor(rippleColor);
+        mBackgroundNormal.setRippleColor(rippleColor);
+        int color = calculateBgColor();
+        if (!animated) {
+            setBackgroundTintColor(color);
+        } else if (color != mCurrentBackgroundTint) {
+            mStartTint = mCurrentBackgroundTint;
+            mTargetTint = color;
+            mBackgroundColorAnimator = ValueAnimator.ofFloat(0.0f, 1.0f);
+            mBackgroundColorAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+                @Override
+                public void onAnimationUpdate(ValueAnimator animation) {
+                    int newColor = NotificationUtils.interpolateColors(mStartTint, mTargetTint,
+                            animation.getAnimatedFraction());
+                    setBackgroundTintColor(newColor);
+                }
+            });
+            mBackgroundColorAnimator.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
+            mBackgroundColorAnimator.setInterpolator(Interpolators.LINEAR);
+            mBackgroundColorAnimator.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    mBackgroundColorAnimator = null;
+                }
+            });
+            mBackgroundColorAnimator.start();
+        }
+    }
+
+    private void setBackgroundTintColor(int color) {
+        mCurrentBackgroundTint = color;
         if (color == mNormalColor) {
             // We don't need to tint a normal notification
             color = 0;
         }
         mBackgroundDimmed.setTint(color);
         mBackgroundNormal.setTint(color);
-        mBackgroundDimmed.setRippleColor(rippleColor);
-        mBackgroundNormal.setRippleColor(rippleColor);
     }
 
     /**
@@ -773,8 +821,12 @@
 
     protected abstract View getContentView();
 
-    public int getBgColor() {
-        if (mBgTint != 0) {
+    public int calculateBgColor() {
+        return calculateBgColor(true /* withTint */);
+    }
+
+    private int calculateBgColor(boolean withTint) {
+        if (withTint && mBgTint != 0) {
             return mBgTint;
         } else if (mShowingLegacyBackground) {
             return mLegacyColor;
@@ -839,7 +891,7 @@
     }
 
     public boolean hasSameBgColor(ActivatableNotificationView otherView) {
-        return getBgColor() == otherView.getBgColor();
+        return calculateBgColor() == otherView.calculateBgColor();
     }
 
     @Override
@@ -863,6 +915,10 @@
                 outlineTranslation);
     }
 
+    public int getBackgroundColorWithoutTint() {
+        return calculateBgColor(false /* withTint */);
+    }
+
     public interface OnActivatedListener {
         void onActivated(ActivatableNotificationView view);
         void onActivationReset(ActivatableNotificationView view);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 12a83fd..c2e1f7d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -411,8 +411,7 @@
     }
 
     public ExpandableNotificationRow getViewAtPosition(float y) {
-        if (!mIsSummaryWithChildren || !mChildrenExpanded
-                || (getNotificationChildren().size() == 1 && isClearable())) {
+        if (!mIsSummaryWithChildren || !mChildrenExpanded) {
             return this;
         } else {
             ExpandableNotificationRow view = mChildrenContainer.getViewAtPosition(y);
@@ -569,6 +568,13 @@
         mPublicLayout.reInflateViews();
     }
 
+    public void setContentBackground(int customBackgroundColor, boolean animate,
+            NotificationContentView notificationContentView) {
+        if (getShowingLayout() == notificationContentView) {
+            setTintColor(customBackgroundColor, animate);
+        }
+    }
+
     public interface ExpansionLogger {
         public void logNotificationExpansion(String key, boolean userAction, boolean expanded);
     }
@@ -1011,7 +1017,6 @@
         }
         mPrivateLayout.updateExpandButtons(isExpandable());
         updateChildrenHeaderAppearance();
-        updateHeaderChildCount();
         updateChildrenVisibility();
     }
 
@@ -1024,7 +1029,11 @@
      * @return whether the view state is currently expanded.
      */
     public boolean isExpanded() {
-        return !mOnKeyguard
+        return isExpanded(false /* allowOnKeyguard */);
+    }
+
+    public boolean isExpanded(boolean allowOnKeyguard) {
+        return (!mOnKeyguard || allowOnKeyguard)
                 && (!hasUserChangedExpansion() && (isSystemExpanded() || isSystemChildExpanded())
                 || isUserExpanded());
     }
@@ -1104,7 +1113,8 @@
         } else {
             animateShowingPublic(delay, duration);
         }
-
+        NotificationContentView showingLayout = getShowingLayout();
+        showingLayout.updateBackgroundColor(animated);
         mPrivateLayout.updateExpandButtons(isExpandable());
         updateClearability();
         mShowingPublicInitialized = true;
@@ -1162,13 +1172,6 @@
         }
     }
 
-    public void updateHeaderChildCount() {
-        if (mIsSummaryWithChildren) {
-            mNotificationHeader.setChildCount(
-                    mChildrenContainer.getNotificationChildren().size());
-        }
-    }
-
     public static void applyTint(View v, int color) {
         int alpha;
         if (color != 0) {
@@ -1280,15 +1283,7 @@
             header.reapply(getContext(), mNotificationHeader);
             mNotificationHeaderWrapper.notifyContentUpdated(mEntry.notification);
         }
-        updateHeaderExpandButton();
         updateChildrenHeaderAppearance();
-        updateHeaderChildCount();
-    }
-
-    private void updateHeaderExpandButton() {
-        if (mIsSummaryWithChildren) {
-            mNotificationHeader.setIsGroupHeader(true /* isGroupHeader*/);
-        }
     }
 
     public void updateChildrenHeaderAppearance() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index b94c15b..3b87577 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -33,6 +33,7 @@
 import com.android.systemui.statusbar.notification.HybridNotificationView;
 import com.android.systemui.statusbar.notification.HybridNotificationViewManager;
 import com.android.systemui.statusbar.notification.NotificationCustomViewWrapper;
+import com.android.systemui.statusbar.notification.NotificationUtils;
 import com.android.systemui.statusbar.notification.NotificationViewWrapper;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
 import com.android.systemui.statusbar.policy.RemoteInputView;
@@ -48,7 +49,7 @@
     private static final int VISIBLE_TYPE_EXPANDED = 1;
     private static final int VISIBLE_TYPE_HEADSUP = 2;
     private static final int VISIBLE_TYPE_SINGLELINE = 3;
-    private static final int UNDEFINED = -1;
+    public static final int UNDEFINED = -1;
 
     private final Rect mClipBounds = new Rect();
     private final int mMinContractedHeight;
@@ -367,6 +368,7 @@
             getViewForVisibleType(visibleType).setVisibility(View.VISIBLE);
             hiddenView.transformTo(shownView, 0.0f);
             mVisibleType = visibleType;
+            updateBackgroundColor(true /* animate */);
         }
         if (mTransformationStartVisibleType != UNDEFINED
                 && mVisibleType != mTransformationStartVisibleType) {
@@ -376,11 +378,29 @@
             float transformationAmount = calculateTransformationAmount();
             shownView.transformFrom(hiddenView, transformationAmount);
             hiddenView.transformTo(shownView, transformationAmount);
+            updateBackgroundTransformation(transformationAmount);
         } else {
             updateViewVisibilities(visibleType);
+            updateBackgroundColor(false);
         }
     }
 
+    private void updateBackgroundTransformation(float transformationAmount) {
+        int endColor = getBackgroundColor(mVisibleType);
+        int startColor = getBackgroundColor(mTransformationStartVisibleType);
+        if (endColor != startColor) {
+            if (startColor == 0) {
+                startColor = mContainingNotification.getBackgroundColorWithoutTint();
+            }
+            if (endColor == 0) {
+                endColor = mContainingNotification.getBackgroundColorWithoutTint();
+            }
+            endColor = NotificationUtils.interpolateColors(startColor, endColor,
+                    transformationAmount);
+        }
+        mContainingNotification.setContentBackground(endColor, false, this);
+    }
+
     private float calculateTransformationAmount() {
         int startHeight = getViewForVisibleType(mTransformationStartVisibleType).getHeight();
         int endHeight = getViewForVisibleType(mVisibleType).getHeight();
@@ -457,9 +477,24 @@
                 updateViewVisibilities(visibleType);
             }
             mVisibleType = visibleType;
+            updateBackgroundColor(animate);
         }
     }
 
+    public void updateBackgroundColor(boolean animate) {
+        int customBackgroundColor = getBackgroundColor(mVisibleType);
+        mContainingNotification.setContentBackground(customBackgroundColor, animate, this);
+    }
+
+    private int getBackgroundColor(int visibleType) {
+        NotificationViewWrapper currentVisibleWrapper = getVisibleWrapper(visibleType);
+        int customBackgroundColor = 0;
+        if (currentVisibleWrapper != null) {
+            customBackgroundColor = currentVisibleWrapper.getCustomBackgroundColor();
+        }
+        return customBackgroundColor;
+    }
+
     private void updateViewVisibilities(int visibleType) {
         boolean contractedVisible = visibleType == VISIBLE_TYPE_CONTRACTED;
         mContractedWrapper.setVisible(contractedVisible);
@@ -530,8 +565,8 @@
         }
     }
 
-    private NotificationViewWrapper getCurrentVisibleWrapper() {
-        switch (mVisibleType) {
+    private NotificationViewWrapper getVisibleWrapper(int visibleType) {
+        switch (visibleType) {
             case VISIBLE_TYPE_EXPANDED:
                 return mExpandedWrapper;
             case VISIBLE_TYPE_HEADSUP:
@@ -549,7 +584,7 @@
     private int calculateVisibleType() {
         if (mUserExpanding) {
             int height = !mIsChildInGroup || isGroupExpanded()
-                    || mContainingNotification.isExpanded()
+                    || mContainingNotification.isExpanded(true /* allowOnKeyguard */)
                     ? mContainingNotification.getMaxContentHeight()
                     : mContainingNotification.getShowingLayout().getMinHeight();
             if (height == 0) {
@@ -588,7 +623,8 @@
             }
         } else {
             if (noExpandedChild || (viewHeight <= mContractedChild.getHeight()
-                    && (!mIsChildInGroup || !mContainingNotification.isExpanded()))) {
+                    && (!mIsChildInGroup
+                            || !mContainingNotification.isExpanded(true /* allowOnKeyguard */)))) {
                 return VISIBLE_TYPE_CONTRACTED;
             } else {
                 return VISIBLE_TYPE_EXPANDED;
@@ -605,7 +641,6 @@
             return;
         }
         mDark = dark;
-        dark = dark && !mShowingLegacyBackground;
         if (mVisibleType == VISIBLE_TYPE_CONTRACTED || !dark) {
             mContractedWrapper.setDark(dark, fade, delay);
         }
@@ -636,6 +671,19 @@
 
     public void setShowingLegacyBackground(boolean showing) {
         mShowingLegacyBackground = showing;
+        updateShowingLegacyBackground();
+    }
+
+    private void updateShowingLegacyBackground() {
+        if (mContractedChild != null) {
+            mContractedWrapper.setShowingLegacyBackground(mShowingLegacyBackground);
+        }
+        if (mExpandedChild != null) {
+            mExpandedWrapper.setShowingLegacyBackground(mShowingLegacyBackground);
+        }
+        if (mHeadsUpChild != null) {
+            mHeadsUpWrapper.setShowingLegacyBackground(mShowingLegacyBackground);
+        }
     }
 
     public void setIsChildInGroup(boolean isChildInGroup) {
@@ -657,6 +705,7 @@
         if (mHeadsUpChild != null) {
             mHeadsUpWrapper.notifyContentUpdated(entry.notification);
         }
+        updateShowingLegacyBackground();
         selectLayout(false /* animate */, true /* force */);
         setDark(mDark, false /* animate */, 0 /* delay */);
     }
@@ -778,7 +827,7 @@
     }
 
     public NotificationHeaderView getVisibleNotificationHeader() {
-        NotificationViewWrapper wrapper = getCurrentVisibleWrapper();
+        NotificationViewWrapper wrapper = getVisibleWrapper(mVisibleType);
         return wrapper == null ? null : wrapper.getNotificationHeader();
     }
 
@@ -806,6 +855,7 @@
             mTransformationStartVisibleType = UNDEFINED;
             mVisibleType = calculateVisibleType();
             updateViewVisibilities(mVisibleType);
+            updateBackgroundColor(false);
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java
index 7f8f20f..49e4ba8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java
@@ -16,8 +16,19 @@
 
 package com.android.systemui.statusbar.notification;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.graphics.Color;
+import android.graphics.ColorMatrixColorFilter;
+import android.graphics.Paint;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.service.notification.StatusBarNotification;
+import android.support.v4.graphics.ColorUtils;
 import android.view.View;
 
+import com.android.systemui.R;
 import com.android.systemui.ViewInvertHelper;
 import com.android.systemui.statusbar.phone.NotificationPanelView;
 
@@ -27,6 +38,11 @@
 public class NotificationCustomViewWrapper extends NotificationViewWrapper {
 
     private final ViewInvertHelper mInvertHelper;
+    private final Paint mGreyPaint = new Paint();
+    private int mBackgroundColor = 0;
+    private static final int CUSTOM_BACKGROUND_TAG = R.id.custom_background_color;
+    private boolean mShouldInvertDark;
+    private boolean mShowingLegacyBackground;
 
     protected NotificationCustomViewWrapper(View view) {
         super(view);
@@ -39,10 +55,46 @@
             return;
         }
         super.setDark(dark, fade, delay);
-        if (fade) {
-            mInvertHelper.fade(dark, delay);
+        if (!mShowingLegacyBackground && mShouldInvertDark) {
+            if (fade) {
+                mInvertHelper.fade(dark, delay);
+            } else {
+                mInvertHelper.update(dark);
+            }
         } else {
-            mInvertHelper.update(dark);
+            mView.setLayerType(dark ? View.LAYER_TYPE_HARDWARE : View.LAYER_TYPE_NONE, null);
+            if (fade) {
+                fadeGrayscale(dark, delay);
+            } else {
+                updateGrayscale(dark);
+            }
+        }
+    }
+
+    protected void fadeGrayscale(final boolean dark, long delay) {
+        startIntensityAnimation(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                updateGrayscaleMatrix((float) animation.getAnimatedValue());
+                mGreyPaint.setColorFilter(new ColorMatrixColorFilter(mGrayscaleColorMatrix));
+                mView.setLayerPaint(mGreyPaint);
+            }
+        }, dark, delay, new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                if (!dark) {
+                    mView.setLayerType(View.LAYER_TYPE_NONE, null);
+                }
+            }
+        });
+    }
+
+    protected void updateGrayscale(boolean dark) {
+        if (dark) {
+            updateGrayscaleMatrix(1f);
+            mGreyPaint.setColorFilter(
+                    new ColorMatrixColorFilter(mGrayscaleColorMatrix));
+            mView.setLayerPaint(mGreyPaint);
         }
     }
 
@@ -51,4 +103,35 @@
         super.setVisible(visible);
         mView.setAlpha(visible ? 1.0f : 0.0f);
     }
+
+    @Override
+    public void notifyContentUpdated(StatusBarNotification notification) {
+        super.notifyContentUpdated(notification);
+        Drawable background = mView.getBackground();
+        mBackgroundColor = 0;
+        if (background instanceof ColorDrawable) {
+            mBackgroundColor = ((ColorDrawable) background).getColor();
+            mView.setBackground(null);
+            mView.setTag(CUSTOM_BACKGROUND_TAG, mBackgroundColor);
+        } else if (mView.getTag(CUSTOM_BACKGROUND_TAG) != null) {
+            mBackgroundColor = (int) mView.getTag(CUSTOM_BACKGROUND_TAG);
+        }
+        mShouldInvertDark = mBackgroundColor == 0 || isColorLight(mBackgroundColor);
+    }
+
+    private boolean isColorLight(int backgroundColor) {
+        return Color.alpha(backgroundColor) == 0
+                || ColorUtils.calculateLuminance(backgroundColor) > 0.5;
+    }
+
+    @Override
+    public int getCustomBackgroundColor() {
+        return mBackgroundColor;
+    }
+
+    @Override
+    public void setShowingLegacyBackground(boolean showing) {
+        super.setShowingLegacyBackground(showing);
+        mShowingLegacyBackground = showing;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java
index 842bd22..b201d8f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java
@@ -47,7 +47,6 @@
  */
 public class NotificationHeaderViewWrapper extends NotificationViewWrapper {
 
-    private final ColorMatrix mGrayscaleColorMatrix = new ColorMatrix();
     private final PorterDuffColorFilter mIconColorFilter = new PorterDuffColorFilter(
             0, PorterDuff.Mode.SRC_ATOP);
     private final int mIconDarkAlpha;
@@ -178,21 +177,6 @@
         }
     }
 
-    protected void startIntensityAnimation(ValueAnimator.AnimatorUpdateListener updateListener,
-            boolean dark, long delay, Animator.AnimatorListener listener) {
-        float startIntensity = dark ? 0f : 1f;
-        float endIntensity = dark ? 1f : 0f;
-        ValueAnimator animator = ValueAnimator.ofFloat(startIntensity, endIntensity);
-        animator.addUpdateListener(updateListener);
-        animator.setDuration(NotificationPanelView.DOZE_ANIMATION_DURATION);
-        animator.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
-        animator.setStartDelay(delay);
-        if (listener != null) {
-            animator.addListener(listener);
-        }
-        animator.start();
-    }
-
     private void fadeIconColorFilter(final ImageView target, boolean dark, long delay) {
         startIntensityAnimation(new ValueAnimator.AnimatorUpdateListener() {
             @Override
@@ -264,10 +248,6 @@
         mNotificationHeader.setOnClickListener(expandable ? onClickListener : null);
     }
 
-    private void updateGrayscaleMatrix(float intensity) {
-        mGrayscaleColorMatrix.setSaturation(1 - intensity);
-    }
-
     private static int interpolateColor(int source, int target, float t) {
         int aSource = Color.alpha(source);
         int rSource = Color.red(source);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java
index 4738657..6ef61ec 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.notification;
 
+import android.graphics.Color;
 import android.widget.ImageView;
 
 import com.android.internal.util.NotificationColorUtil;
@@ -38,4 +39,12 @@
     public static float interpolate(float start, float end, float amount) {
         return start * (1.0f - amount) + end * amount;
     }
+
+    public static int interpolateColors(int startColor, int endColor, float amount) {
+        return Color.argb(
+                (int) interpolate(Color.alpha(startColor), Color.alpha(endColor), amount),
+                (int) interpolate(Color.red(startColor), Color.red(endColor), amount),
+                (int) interpolate(Color.green(startColor), Color.green(endColor), amount),
+                (int) interpolate(Color.blue(startColor), Color.blue(endColor), amount));
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
index 0df0d26..ebff69d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
@@ -16,13 +16,19 @@
 
 package com.android.systemui.statusbar.notification;
 
+import android.animation.Animator;
+import android.animation.ValueAnimator;
 import android.content.Context;
+import android.graphics.ColorMatrix;
 import android.service.notification.StatusBarNotification;
 import android.view.NotificationHeaderView;
 import android.view.View;
 
+import com.android.systemui.Interpolators;
 import com.android.systemui.statusbar.CrossFadeHelper;
+import com.android.systemui.statusbar.NotificationContentView;
 import com.android.systemui.statusbar.TransformableView;
+import com.android.systemui.statusbar.phone.NotificationPanelView;
 
 /**
  * Wraps the actual notification content view; used to implement behaviors which are different for
@@ -30,6 +36,7 @@
  */
 public abstract class NotificationViewWrapper implements TransformableView {
 
+    protected final ColorMatrix mGrayscaleColorMatrix = new ColorMatrix();
     protected final View mView;
     protected boolean mDark;
     protected boolean mDarkInitialized = false;
@@ -75,6 +82,26 @@
         mDarkInitialized = false;
     };
 
+
+    protected void startIntensityAnimation(ValueAnimator.AnimatorUpdateListener updateListener,
+            boolean dark, long delay, Animator.AnimatorListener listener) {
+        float startIntensity = dark ? 0f : 1f;
+        float endIntensity = dark ? 1f : 0f;
+        ValueAnimator animator = ValueAnimator.ofFloat(startIntensity, endIntensity);
+        animator.addUpdateListener(updateListener);
+        animator.setDuration(NotificationPanelView.DOZE_ANIMATION_DURATION);
+        animator.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
+        animator.setStartDelay(delay);
+        if (listener != null) {
+            animator.addListener(listener);
+        }
+        animator.start();
+    }
+
+    protected void updateGrayscaleMatrix(float intensity) {
+        mGrayscaleColorMatrix.setSaturation(1 - intensity);
+    }
+
     /**
      * Update the appearance of the expand button.
      *
@@ -122,4 +149,11 @@
         mView.animate().cancel();
         mView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
     }
+
+    public int getCustomBackgroundColor() {
+        return 0;
+    }
+
+    public void setShowingLegacyBackground(boolean showing) {
+    }
 }
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 073a848..7856f6c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -772,10 +772,21 @@
         ScrimView scrimInFront = (ScrimView) mStatusBarWindow.findViewById(R.id.scrim_in_front);
         View headsUpScrim = mStatusBarWindow.findViewById(R.id.heads_up_scrim);
         mScrimController = SystemUIFactory.getInstance().createScrimController(
-                scrimBehind, scrimInFront, headsUpScrim, mScrimSrcModeEnabled);
+                scrimBehind, scrimInFront, headsUpScrim);
+        if (mScrimSrcModeEnabled) {
+            Runnable runnable = new Runnable() {
+                @Override
+                public void run() {
+                    boolean asSrc = mBackdrop.getVisibility() != View.VISIBLE;
+                    mScrimController.setDrawBehindAsSrc(asSrc);
+                    mStackScroller.setDrawBackgroundAsSrc(asSrc);
+                }
+            };
+            mBackdrop.setOnVisibilityChangedRunnable(runnable);
+            runnable.run();
+        }
         mHeadsUpManager.addListener(mScrimController);
         mStackScroller.setScrimController(mScrimController);
-        mScrimController.setBackDropView(mBackdrop);
         mStatusBarView.setScrimController(mScrimController);
         mDozeScrimController = new DozeScrimController(mScrimController, context);
 
@@ -1466,6 +1477,9 @@
             mStackScroller.removeView(remove);
             mStackScroller.setChildTransferInProgress(false);
         }
+
+        removeNotificationChildren();
+
         for (int i=0; i<toShow.size(); i++) {
             View v = toShow.get(i);
             if (v.getParent() == null) {
@@ -1473,6 +1487,8 @@
             }
         }
 
+        addNotificationChildrenAndSort();
+
         // So after all this work notifications still aren't sorted correctly.
         // Let's do that now by advancing through toShow and mStackScroller in
         // lock-step, making sure mStackScroller matches what we see in toShow.
@@ -1494,9 +1510,6 @@
 
         }
 
-        // lets handle the child notifications now
-        updateNotificationShadeForChildren();
-
         // clear the map again for the next usage
         mTmpChildOrderMap.clear();
 
@@ -1522,34 +1535,7 @@
                 && !ONLY_CORE_APPS);
     }
 
-    private void updateNotificationShadeForChildren() {
-        // First let's remove all children which don't belong in the parents
-        ArrayList<ExpandableNotificationRow> toRemove = new ArrayList<>();
-        for (int i = 0; i < mStackScroller.getChildCount(); i++) {
-            View view = mStackScroller.getChildAt(i);
-            if (!(view instanceof ExpandableNotificationRow)) {
-                // We don't care about non-notification views.
-                continue;
-            }
-
-            ExpandableNotificationRow parent = (ExpandableNotificationRow) view;
-            List<ExpandableNotificationRow> children = parent.getNotificationChildren();
-            List<ExpandableNotificationRow> orderedChildren = mTmpChildOrderMap.get(parent);
-
-            if (children != null) {
-                toRemove.clear();
-                for (ExpandableNotificationRow childRow : children) {
-                    if (orderedChildren == null || !orderedChildren.contains(childRow)) {
-                        toRemove.add(childRow);
-                    }
-                }
-                for (ExpandableNotificationRow remove : toRemove) {
-                    parent.removeChildNotification(remove);
-                    mStackScroller.notifyGroupChildRemoved(remove);
-                }
-            }
-        }
-
+    private void addNotificationChildrenAndSort() {
         // Let's now add all notification children which are missing
         boolean orderChanged = false;
         for (int i = 0; i < mStackScroller.getChildCount(); i++) {
@@ -1580,6 +1566,39 @@
         }
     }
 
+    private void removeNotificationChildren() {
+        // First let's remove all children which don't belong in the parents
+        ArrayList<ExpandableNotificationRow> toRemove = new ArrayList<>();
+        for (int i = 0; i < mStackScroller.getChildCount(); i++) {
+            View view = mStackScroller.getChildAt(i);
+            if (!(view instanceof ExpandableNotificationRow)) {
+                // We don't care about non-notification views.
+                continue;
+            }
+
+            ExpandableNotificationRow parent = (ExpandableNotificationRow) view;
+            List<ExpandableNotificationRow> children = parent.getNotificationChildren();
+            List<ExpandableNotificationRow> orderedChildren = mTmpChildOrderMap.get(parent);
+
+            if (children != null) {
+                toRemove.clear();
+                for (ExpandableNotificationRow childRow : children) {
+                    if (orderedChildren == null || !orderedChildren.contains(childRow)) {
+                        toRemove.add(childRow);
+                    }
+                }
+                for (ExpandableNotificationRow remove : toRemove) {
+                    parent.removeChildNotification(remove);
+                    if (mNotificationData.get(remove.getStatusBarNotification().getKey()) == null) {
+                        // We only want to add an animation if the view is completely removed
+                        // otherwise it's just a transfer
+                        mStackScroller.notifyGroupChildRemoved(remove);
+                    }
+                }
+            }
+        }
+    }
+
     @Override
     public void addQsTile(ComponentName tile) {
         mQSPanel.getHost().addTile(tile);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index fe76ae7..1a557e4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -30,7 +30,6 @@
 import android.view.animation.PathInterpolator;
 
 import com.android.systemui.R;
-import com.android.systemui.statusbar.BackDropView;
 import com.android.systemui.statusbar.ExpandableNotificationRow;
 import com.android.systemui.statusbar.NotificationData;
 import com.android.systemui.statusbar.ScrimView;
@@ -75,8 +74,6 @@
     private long mAnimationDelay;
     private Runnable mOnAnimationFinished;
     private final Interpolator mInterpolator = new DecelerateInterpolator();
-    private BackDropView mBackDropView;
-    private boolean mScrimSrcEnabled;
     private boolean mDozing;
     private float mDozeInFrontAlpha;
     private float mDozeBehindAlpha;
@@ -90,14 +87,12 @@
     private boolean mSkipFirstFrame;
     private boolean mDontAnimateBouncerChanges;
 
-    public ScrimController(ScrimView scrimBehind, ScrimView scrimInFront, View headsUpScrim,
-            boolean scrimSrcEnabled) {
+    public ScrimController(ScrimView scrimBehind, ScrimView scrimInFront, View headsUpScrim) {
         mScrimBehind = scrimBehind;
         mScrimInFront = scrimInFront;
         mHeadsUpScrim = headsUpScrim;
         final Context context = scrimBehind.getContext();
         mUnlockMethodCache = UnlockMethodCache.getInstance(context);
-        mScrimSrcEnabled = scrimSrcEnabled;
         updateHeadsUpScrim(false);
     }
 
@@ -378,19 +373,7 @@
         return scrim.getTag(TAG_KEY_ANIM) != null;
     }
 
-    public void setBackDropView(BackDropView backDropView) {
-        mBackDropView = backDropView;
-        mBackDropView.setOnVisibilityChangedRunnable(new Runnable() {
-            @Override
-            public void run() {
-                updateScrimBehindDrawingMode();
-            }
-        });
-        updateScrimBehindDrawingMode();
-    }
-
-    private void updateScrimBehindDrawingMode() {
-        boolean asSrc = mBackDropView.getVisibility() != View.VISIBLE && mScrimSrcEnabled;
+    public void setDrawBehindAsSrc(boolean asSrc) {
         mScrimBehind.setDrawAsSrc(asSrc);
     }
 
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 7955733..9d50ab4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
@@ -511,7 +511,7 @@
                 break;
             }
             ExpandableNotificationRow child = mChildren.get(i);
-            float childHeight = child.isExpanded()
+            float childHeight = child.isExpanded(true /* allowOnKeyguard */)
                     ? child.getMaxExpandHeight()
                     : child.getShowingLayout().getMinHeight(true /* likeGroupExpanded */);
             maxContentHeight += childHeight;
@@ -532,7 +532,7 @@
         int childCount = mChildren.size();
         for (int i = 0; i < childCount; i++) {
             ExpandableNotificationRow child = mChildren.get(i);
-            float childHeight = child.isExpanded()
+            float childHeight = child.isExpanded(true /* allowOnKeyguard */)
                     ? child.getMaxExpandHeight()
                     : child.getShowingLayout().getMinHeight(true /* likeGroupExpanded */);
             float singleLineHeight = child.getShowingLayout().getMinHeight(
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 aa444f5..cca3746 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -18,7 +18,6 @@
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
 import android.animation.PropertyValuesHolder;
 import android.animation.TimeAnimator;
@@ -324,6 +323,7 @@
             }
         }
     };
+    private PorterDuffXfermode mSrcMode = new PorterDuffXfermode(PorterDuff.Mode.SRC);
 
     public NotificationStackScrollLayout(Context context) {
         this(context, null);
@@ -359,7 +359,6 @@
             mDebugPaint.setStyle(Paint.Style.STROKE);
         }
         mFalsingManager = FalsingManager.getInstance(context);
-        mBackgroundPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
     }
 
     @Override
@@ -427,6 +426,11 @@
                 R.dimen.min_top_overscroll_to_qs);
     }
 
+    public void setDrawBackgroundAsSrc(boolean asSrc) {
+        mBackgroundPaint.setXfermode(asSrc ? mSrcMode : null);
+        invalidate();
+    }
+
     private void notifyHeightChangeListener(ExpandableView view) {
         if (mOnHeightChangedListener != null) {
             mOnHeightChangedListener.onHeightChanged(view, false /* needsAnimation */);
@@ -774,12 +778,15 @@
         if (child instanceof ExpandableNotificationRow) {
             ExpandableNotificationRow row = (ExpandableNotificationRow) child;
             ExpandableNotificationRow parent = row.getNotificationParent();
-            if (mGearExposedView != null && parent != null
-                    && parent.areChildrenExpanded() && mGearExposedView == parent) {
+            if (parent != null && parent.areChildrenExpanded()
+                    && (mGearExposedView == parent
+                        || (parent.getNotificationChildren().size() == 1
+                                && parent.isClearable()))) {
                 // In this case the group is expanded and showing the gear for the
                 // group, further interaction should apply to the group, not any
-                // child notifications so we use the parent of the child.
-                child = row.getNotificationParent();
+                // child notifications so we use the parent of the child. We also do the same
+                // if we only have a single child.
+                child = parent;
             }
         }
         return child;
@@ -857,7 +864,7 @@
     public boolean canChildBeExpanded(View v) {
         return v instanceof ExpandableNotificationRow
                 && ((ExpandableNotificationRow) v).isExpandable()
-                && !((ExpandableNotificationRow) v).isHeadsUp();
+                && (mIsExpanded || !((ExpandableNotificationRow) v).isPinned());
     }
 
     public void setUserExpandedChild(View v, boolean userExpanded) {