Update the notification templates

Most of the notification templates have been updated.
Some cases like media notifications don't yet work well
but will be fixed in a later CL.

Bug: 25376106
Change-Id: I26c366e58ebba3852cea20de6fca311bd302bb24
diff --git a/packages/SystemUI/res/drawable/notification_expand_more.xml b/packages/SystemUI/res/drawable/notification_expand_more.xml
index 5aa7937..430fb0d 100644
--- a/packages/SystemUI/res/drawable/notification_expand_more.xml
+++ b/packages/SystemUI/res/drawable/notification_expand_more.xml
@@ -12,7 +12,7 @@
     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.
+    limitations under the License._more
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:width="22.0dp"
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 82192fe..6fa36d2 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -49,10 +49,10 @@
     <dimen name="notification_single_line_height">32sp</dimen>
 
     <!-- Height of a small notification in the status bar -->
-    <dimen name="notification_min_height">64dp</dimen>
+    <dimen name="notification_min_height">84dp</dimen>
 
     <!-- Height of a large notification in the status bar -->
-    <dimen name="notification_max_height">256dp</dimen>
+    <dimen name="notification_max_height">276dp</dimen>
 
     <!-- Height of a medium notification in the status bar -->
     <dimen name="notification_mid_height">128dp</dimen>
@@ -258,7 +258,7 @@
 
     <!-- bottom_stack_peek_amount + notification_min_height
          + notification_collapse_second_card_padding -->
-    <dimen name="min_stack_height">84dp</dimen>
+    <dimen name="min_stack_height">104dp</dimen>
 
     <!-- The height of the area before the bottom stack in which the notifications slow down -->
     <dimen name="bottom_stack_slow_down_length">12dp</dimen>
@@ -276,7 +276,7 @@
     <dimen name="notification_padding_dimmed">0dp</dimen>
 
     <!-- The padding between the individual notification cards. -->
-    <dimen name="notification_padding">4dp</dimen>
+    <dimen name="notification_padding">2dp</dimen>
 
     <!-- The minimum amount of top overscroll to go to the quick settings. -->
     <dimen name="min_top_overscroll_to_qs">36dp</dimen>
@@ -296,7 +296,7 @@
     <!-- Falsing threshold used when dismissing notifications from the lockscreen. -->
     <dimen name="swipe_helper_falsing_threshold">70dp</dimen>
 
-    <dimen name="notifications_top_padding">8dp</dimen>
+    <dimen name="notifications_top_padding">4dp</dimen>
     
     <!-- Minimum distance the user has to drag down to go to the full shade. -->
     <dimen name="keyguard_drag_down_min_distance">100dp</dimen>
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
index a12a3f1..19b65f7 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
@@ -36,7 +36,6 @@
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.util.Slog;
-import android.view.View;
 
 import com.android.systemui.R;
 import com.android.systemui.statusbar.phone.PhoneStatusBar;
@@ -162,9 +161,6 @@
                 .setColor(mContext.getColor(
                         com.android.internal.R.color.system_notification_accent_color));
         final Notification n = nb.build();
-        if (n.headsUpContentView != null) {
-            n.headsUpContentView.setViewVisibility(com.android.internal.R.id.right_icon, View.GONE);
-        }
         mNoMan.notifyAsUser(TAG_NOTIFICATION, R.id.notification_power, n, UserHandle.ALL);
     }
 
@@ -200,9 +196,6 @@
             mPlaySound = false;
         }
         final Notification n = nb.build();
-        if (n.headsUpContentView != null) {
-            n.headsUpContentView.setViewVisibility(com.android.internal.R.id.right_icon, View.GONE);
-        }
         mNoMan.notifyAsUser(TAG_NOTIFICATION, R.id.notification_power, n, UserHandle.ALL);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 723989a..182fc1b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -40,7 +40,6 @@
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.database.ContentObserver;
-import android.graphics.PorterDuff;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.Icon;
 import android.os.AsyncTask;
@@ -1498,18 +1497,6 @@
 
             Drawable iconDrawable = StatusBarIconView.getIcon(mContext, ic);
             icon.setImageDrawable(iconDrawable);
-            if (entry.targetSdk >= Build.VERSION_CODES.LOLLIPOP
-                    || mNotificationColorUtil.isGrayscaleIcon(iconDrawable)) {
-                icon.setBackgroundResource(
-                        com.android.internal.R.drawable.notification_icon_legacy_bg);
-                int padding = mContext.getResources().getDimensionPixelSize(
-                        com.android.internal.R.dimen.notification_large_icon_circle_padding);
-                icon.setPadding(padding, padding, padding, padding);
-                if (sbn.getNotification().color != Notification.COLOR_DEFAULT) {
-                    icon.getBackground().setColorFilter(
-                            sbn.getNotification().color, PorterDuff.Mode.SRC_ATOP);
-                }
-            }
 
             if (profileBadge != null) {
                 Drawable profileDrawable = mContext.getPackageManager().getUserBadgeForDensity(
@@ -1536,11 +1523,6 @@
                         R.style.TextAppearance_Material_Notification_Parenthetical);
             }
 
-            int topPadding = Notification.Builder.calculateTopPadding(mContext,
-                    false /* hasThreeLines */,
-                    mContext.getResources().getConfiguration().fontScale);
-            title.setPadding(0, topPadding, 0, 0);
-
             contentContainerPublic.setContractedChild(publicViewLocal);
             entry.autoRedacted = true;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 3603900..02632d5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -452,6 +452,8 @@
         super.onFinishInflate();
         mPublicLayout = (NotificationContentView) findViewById(R.id.expandedPublic);
         mPrivateLayout = (NotificationContentView) findViewById(R.id.expanded);
+        mPublicLayout.setContainingNotification(this);
+        mPrivateLayout.setContainingNotification(this);
         mGutsStub = (ViewStub) findViewById(R.id.notification_guts_stub);
         mGutsStub.setOnInflateListener(new ViewStub.OnInflateListener() {
             @Override
@@ -534,6 +536,7 @@
 
     public void setExpandable(boolean expandable) {
         mExpandable = expandable;
+        mPrivateLayout.updateExpandButtons();
     }
 
     /**
@@ -686,6 +689,7 @@
         if (mIsSummaryWithChildren && mChildrenContainer == null) {
             mChildrenContainerStub.inflate();
         }
+        mPrivateLayout.updateExpandButtons();
         updateNotificationHeader();
         updateChildrenVisibility(true);
     }
@@ -771,6 +775,7 @@
             animateShowingPublic(delay, duration);
         }
 
+        mPrivateLayout.updateExpandButtons();
         updateVetoButton();
         mShowingPublicInitialized = true;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index 5aedaf1..17d9856 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -77,7 +77,9 @@
     private boolean mIsHeadsUp;
     private boolean mShowingLegacyBackground;
     private boolean mIsChildInGroup;
+    private ExpandableNotificationRow mContainingNotification;
     private StatusBarNotification mStatusBarNotification;
+    private NotificationGroupManager mGroupManager;
 
     private final ViewTreeObserver.OnPreDrawListener mEnableAnimationPredrawListener
             = new ViewTreeObserver.OnPreDrawListener() {
@@ -96,7 +98,17 @@
                     mRoundRectRadius);
         }
     };
-    private NotificationGroupManager mGroupManager;
+    private OnClickListener mExpandClickListener = new OnClickListener() {
+        @Override
+        public void onClick(View v) {
+            if (mGroupManager.isSummaryOfGroup(mStatusBarNotification)) {
+                mGroupManager.toggleGroupExpansion(mStatusBarNotification);
+            } else {
+                mContainingNotification.setUserExpanded(!mContainingNotification.isExpanded());
+                mContainingNotification.notifyHeightChanged(true);
+            }
+        }
+    };
 
     public NotificationContentView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -488,6 +500,10 @@
         updateSingleLineView();
     }
 
+    public void setContainingNotification(ExpandableNotificationRow notification) {
+        mContainingNotification = notification;
+    }
+
     public void setStatusBarNotification(StatusBarNotification statusBarNotification) {
         mStatusBarNotification = statusBarNotification;
         updateSingleLineView();
@@ -515,4 +531,19 @@
     public void setGroupManager(NotificationGroupManager groupManager) {
         mGroupManager = groupManager;
     }
+
+    public void updateExpandButtons() {
+        if (mExpandedChild != null) {
+            mExpandedWrapper.updateExpandability(mContainingNotification.isExpandable(),
+                    mExpandClickListener);
+        }
+        if (mContractedChild != null) {
+            mContractedWrapper.updateExpandability(mContainingNotification.isExpandable(),
+                    mExpandClickListener);
+        }
+        if (mHeadsUpChild != null) {
+            mHeadsUpWrapper.updateExpandability(mContainingNotification.isExpandable(),
+                    mExpandClickListener);
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationTemplateViewWrapper.java
index af6ccd8..dff3500 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationTemplateViewWrapper.java
@@ -26,9 +26,12 @@
 import android.graphics.ColorMatrixColorFilter;
 import android.graphics.PorterDuff;
 import android.graphics.PorterDuffColorFilter;
+import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.text.TextUtils;
+import android.view.MotionEvent;
 import android.view.View;
+import android.view.ViewConfiguration;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
 import android.widget.ImageView;
@@ -38,6 +41,8 @@
 import com.android.systemui.ViewInvertHelper;
 import com.android.systemui.statusbar.phone.NotificationPanelView;
 
+import java.util.ArrayList;
+
 /**
  * Wraps a notification view inflated from a template.
  */
@@ -47,26 +52,32 @@
     private final PorterDuffColorFilter mIconColorFilter = new PorterDuffColorFilter(
             0, PorterDuff.Mode.SRC_ATOP);
     private final int mIconDarkAlpha;
-    private final int mIconBackgroundDarkColor;
+    private final int mIconDarkColor;
     private final Interpolator mLinearOutSlowInInterpolator;
 
-    private int mIconBackgroundColor;
+    private int mColor;
     private ViewInvertHelper mInvertHelper;
     private ImageView mIcon;
     protected ImageView mPicture;
 
-    /** Whether the icon needs to be forced grayscale when in dark mode. */
+    /**
+     * Whether the icon needs to be forced grayscale when in dark mode.
+     */
     private boolean mIconForceGraysaleWhenDark;
     private TextView mSubText;
     private TextView mInfoText;
     private View mProfileBadge;
     private View mThirdLineDivider;
     private View mThirdLine;
+    private ImageView mExpandButton;
+    private View mNotificationHeader;
+    private View.OnClickListener mExpandClickListener;
+    private HeaderTouchListener mHeaderTouchListener;
 
     protected NotificationTemplateViewWrapper(Context ctx, View view) {
         super(view);
         mIconDarkAlpha = ctx.getResources().getInteger(R.integer.doze_small_icon_alpha);
-        mIconBackgroundDarkColor =
+        mIconDarkColor =
                 ctx.getColor(R.color.doze_small_icon_background_color);
         mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(ctx,
                 android.R.interpolator.linear_out_slow_in);
@@ -78,16 +89,25 @@
         mInvertHelper = mainColumn != null
                 ? new ViewInvertHelper(mainColumn, NotificationPanelView.DOZE_ANIMATION_DURATION)
                 : null;
-        ImageView largeIcon = (ImageView) mView.findViewById(com.android.internal.R.id.icon);
-        ImageView rightIcon = (ImageView) mView.findViewById(com.android.internal.R.id.right_icon);
-        mIcon = resolveIcon(largeIcon, rightIcon);
-        mPicture = resolvePicture(largeIcon);
-        mIconBackgroundColor = resolveBackgroundColor(mIcon);
+        mIcon = (ImageView) mView.findViewById(com.android.internal.R.id.icon);
+        mPicture = (ImageView) mView.findViewById(com.android.internal.R.id.right_icon);
         mSubText = (TextView) mView.findViewById(com.android.internal.R.id.text);
         mInfoText = (TextView) mView.findViewById(com.android.internal.R.id.info);
         mProfileBadge = mView.findViewById(com.android.internal.R.id.profile_badge_line3);
         mThirdLineDivider = mView.findViewById(com.android.internal.R.id.overflow_divider);
         mThirdLine = mView.findViewById(com.android.internal.R.id.line3);
+        mExpandButton = (ImageView) mView.findViewById(com.android.internal.R.id.expand_button);
+        mColor = resolveColor(mExpandButton);
+        mNotificationHeader = mView.findViewById(com.android.internal.R.id.notification_header);
+        // Post to make sure the parent lays out its children before we get their bounds
+        mHeaderTouchListener = new HeaderTouchListener();
+        mExpandButton.post(new Runnable() {
+            @Override
+            public void run() {
+                // let's set up our touch regions
+                mHeaderTouchListener.bindTouchRects(mNotificationHeader, mIcon, mExpandButton);
+            }
+        });
 
         // If the icon already has a color filter, we assume that we already forced the icon to be
         // white when we created the notification.
@@ -95,21 +115,9 @@
         mIconForceGraysaleWhenDark = iconDrawable != null && iconDrawable.getColorFilter() != null;
     }
 
-    private ImageView resolveIcon(ImageView largeIcon, ImageView rightIcon) {
-        return largeIcon != null && largeIcon.getBackground() != null ? largeIcon
-                : rightIcon != null && rightIcon.getVisibility() == View.VISIBLE ? rightIcon
-                : null;
-    }
-
-    private ImageView resolvePicture(ImageView largeIcon) {
-        return largeIcon != null && largeIcon.getBackground() == null
-                ? largeIcon
-                : null;
-    }
-
-    private int resolveBackgroundColor(ImageView icon) {
-        if (icon != null && icon.getBackground() != null) {
-            ColorFilter filter = icon.getBackground().getColorFilter();
+    private int resolveColor(ImageView icon) {
+        if (icon != null && icon.getDrawable() != null) {
+            ColorFilter filter = icon.getDrawable().getColorFilter();
             if (filter instanceof PorterDuffColorFilter) {
                 return ((PorterDuffColorFilter) filter).getColor();
             }
@@ -218,14 +226,14 @@
     }
 
     private void updateIconColorFilter(ImageView target, float intensity) {
-        int color = interpolateColor(mIconBackgroundColor, mIconBackgroundDarkColor, intensity);
+        int color = interpolateColor(mColor, mIconDarkColor, intensity);
         mIconColorFilter.setColor(color);
-        Drawable background = target.getBackground();
+        Drawable iconDrawable = target.getDrawable();
 
         // The background might be null for legacy notifications. Also, the notification might have
         // been modified during the animation, so background might be null here.
-        if (background != null) {
-            background.mutate().setColorFilter(mIconColorFilter);
+        if (iconDrawable != null) {
+            iconDrawable.mutate().setColorFilter(mIconColorFilter);
         }
     }
 
@@ -279,6 +287,13 @@
         }
     }
 
+    @Override
+    public void updateExpandability(boolean expandable, View.OnClickListener onClickListener) {
+        mExpandButton.setVisibility(expandable ? View.VISIBLE : View.GONE);
+        mNotificationHeader.setOnTouchListener(expandable ? mHeaderTouchListener : null);
+        mExpandClickListener = onClickListener;
+    }
+
     private void updateGrayscaleMatrix(float intensity) {
         mGrayscaleColorMatrix.setSaturation(1 - intensity);
     }
@@ -298,4 +313,91 @@
                 (int) (gSource * (1f - t) + gTarget * t),
                 (int) (bSource * (1f - t) + bTarget * t));
     }
+
+    public class HeaderTouchListener implements View.OnTouchListener {
+
+        private final ArrayList<Rect> mTouchRects = new ArrayList<>();
+        private int mTouchSlop;
+        private boolean mTrackGesture;
+        private float mDownX;
+        private float mDownY;
+
+        public HeaderTouchListener() {
+        }
+
+        public void bindTouchRects(View parent, View icon, View expandButton) {
+            mTouchRects.clear();
+            addRectAroundViewView(icon);
+            addRectAroundViewView(expandButton);
+            addInBetweenRect(parent);
+            mTouchSlop = ViewConfiguration.get(parent.getContext()).getScaledTouchSlop();
+        }
+
+        private void addInBetweenRect(View parent) {
+            final Rect r = new Rect();
+            r.top = 0;
+            r.bottom = (int) (32 * parent.getResources().getDisplayMetrics().density);
+            Rect leftRect = mTouchRects.get(0);
+            r.left = leftRect.right;
+            Rect rightRect = mTouchRects.get(1);
+            r.right = rightRect.left;
+            mTouchRects.add(r);
+        }
+
+        private void addRectAroundViewView(View view) {
+            final Rect r = getRectAroundView(view);
+            mTouchRects.add(r);
+        }
+
+        private Rect getRectAroundView(View view) {
+            float size = 48 * view.getResources().getDisplayMetrics().density;
+            final Rect r = new Rect();
+            r.top = (int) ((view.getTop() + view.getBottom()) / 2.0f - size / 2.0f);
+            r.bottom = (int) (r.top + size);
+            r.left = (int) ((view.getLeft() + view.getRight()) / 2.0f - size / 2.0f);
+            r.right = (int) (r.left + size);
+            return r;
+        }
+
+        @Override
+        public boolean onTouch(View v, MotionEvent event) {
+            float x = event.getX();
+            float y = event.getY();
+            switch (event.getActionMasked() & MotionEvent.ACTION_MASK) {
+                case MotionEvent.ACTION_DOWN:
+                    mTrackGesture = false;
+                    if (isInside(x, y)) {
+                        mTrackGesture = true;
+                        return true;
+                    }
+                    break;
+                case MotionEvent.ACTION_MOVE:
+                    if (mTrackGesture) {
+                        if (Math.abs(mDownX - x) > mTouchSlop
+                                || Math.abs(mDownY - y) > mTouchSlop) {
+                            mTrackGesture = false;
+                        }
+                    }
+                    break;
+                case MotionEvent.ACTION_UP:
+                    if (mTrackGesture) {
+                        mExpandClickListener.onClick(mNotificationHeader);
+                    }
+                    break;
+            }
+            return mTrackGesture;
+        }
+
+        private boolean isInside(float x, float y) {
+            for (int i = 0; i < mTouchRects.size(); i++) {
+                Rect r = mTouchRects.get(i);
+                if (r.contains((int) x, (int) y)) {
+                    mDownX = x;
+                    mDownY = y;
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewWrapper.java
index 9bce548..2fb3127 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewWrapper.java
@@ -83,4 +83,12 @@
     public void setSubTextVisible(boolean visible) {
         mSubTextVisible = visible;
     }
+
+    /**
+     * Update the appearance of the expand button.
+     *
+     * @param expandable should this view be expandable
+     * @param onClickListener the listener to invoke when the expand affordance is clicked on
+     */
+    public void updateExpandability(boolean expandable, View.OnClickListener onClickListener) {}
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
index 65ca95b..dba027b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -42,7 +42,7 @@
     private static final int MAX_ITEMS_IN_BOTTOM_STACK = 3;
     private static final int MAX_ITEMS_IN_TOP_STACK = 3;
 
-    public static final float DIMMED_SCALE = 0.95f;
+    public static final float DIMMED_SCALE = 0.98f;
 
     private int mPaddingBetweenElements;
     private int mCollapsedSize;