19c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek/*
29c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek * Copyright (C) 2015 The Android Open Source Project
39c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek *
49c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek * Licensed under the Apache License, Version 2.0 (the "License");
59c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek * you may not use this file except in compliance with the License.
69c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek * You may obtain a copy of the License at
79c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek *
89c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek *      http://www.apache.org/licenses/LICENSE-2.0
99c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek *
109c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek * Unless required by applicable law or agreed to in writing, software
119c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek * distributed under the License is distributed on an "AS IS" BASIS,
129c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek * See the License for the specific language governing permissions and
149c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek * limitations under the License
159c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek */
169c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek
170ffbda62e55ad390e05e6c3ff52e1378e420285cSelim Cinekpackage com.android.systemui.statusbar.notification;
189c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek
199c7712d45ccec56a80873a83e56a83f810624b43Selim Cinekimport android.animation.Animator;
209c7712d45ccec56a80873a83e56a83f810624b43Selim Cinekimport android.animation.AnimatorListenerAdapter;
219c7712d45ccec56a80873a83e56a83f810624b43Selim Cinekimport android.animation.ValueAnimator;
229c7712d45ccec56a80873a83e56a83f810624b43Selim Cinekimport android.content.Context;
239c7712d45ccec56a80873a83e56a83f810624b43Selim Cinekimport android.graphics.Color;
249c7712d45ccec56a80873a83e56a83f810624b43Selim Cinekimport android.graphics.ColorFilter;
259c7712d45ccec56a80873a83e56a83f810624b43Selim Cinekimport android.graphics.ColorMatrixColorFilter;
269c7712d45ccec56a80873a83e56a83f810624b43Selim Cinekimport android.graphics.PorterDuff;
279c7712d45ccec56a80873a83e56a83f810624b43Selim Cinekimport android.graphics.PorterDuffColorFilter;
289c7712d45ccec56a80873a83e56a83f810624b43Selim Cinekimport android.graphics.drawable.Drawable;
294ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinekimport android.service.notification.StatusBarNotification;
3075524417ac507597b19abb2a91389044bec682adAdrian Roosimport android.util.ArraySet;
319c7712d45ccec56a80873a83e56a83f810624b43Selim Cinekimport android.view.NotificationHeaderView;
329c7712d45ccec56a80873a83e56a83f810624b43Selim Cinekimport android.view.View;
330ffbda62e55ad390e05e6c3ff52e1378e420285cSelim Cinekimport android.view.ViewGroup;
349c7712d45ccec56a80873a83e56a83f810624b43Selim Cinekimport android.widget.ImageView;
359c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek
369c7712d45ccec56a80873a83e56a83f810624b43Selim Cinekimport com.android.systemui.R;
379c7712d45ccec56a80873a83e56a83f810624b43Selim Cinekimport com.android.systemui.ViewInvertHelper;
387d1c63e66a2e19bf32249f52c56e563eae4c6819Selim Cinekimport com.android.systemui.statusbar.ExpandableNotificationRow;
390ffbda62e55ad390e05e6c3ff52e1378e420285cSelim Cinekimport com.android.systemui.statusbar.TransformableView;
400ffbda62e55ad390e05e6c3ff52e1378e420285cSelim Cinekimport com.android.systemui.statusbar.ViewTransformationHelper;
419c7712d45ccec56a80873a83e56a83f810624b43Selim Cinekimport com.android.systemui.statusbar.phone.NotificationPanelView;
429c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek
430ffbda62e55ad390e05e6c3ff52e1378e420285cSelim Cinekimport java.util.Stack;
449c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek
459c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek/**
469c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek * Wraps a notification header view.
479c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek */
489c7712d45ccec56a80873a83e56a83f810624b43Selim Cinekpublic class NotificationHeaderViewWrapper extends NotificationViewWrapper {
499c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek
509c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek    private final PorterDuffColorFilter mIconColorFilter = new PorterDuffColorFilter(
519c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek            0, PorterDuff.Mode.SRC_ATOP);
529c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek    private final int mIconDarkAlpha;
539c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek    private final int mIconDarkColor = 0xffffffff;
549c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek    protected final ViewInvertHelper mInvertHelper;
559c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek
564ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek    protected final ViewTransformationHelper mTransformationHelper;
574ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek
589c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek    protected int mColor;
599c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek    private ImageView mIcon;
609c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek
619c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek    private ImageView mExpandButton;
629c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek    private NotificationHeaderView mNotificationHeader;
639c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek
647d1c63e66a2e19bf32249f52c56e563eae4c6819Selim Cinek    protected NotificationHeaderViewWrapper(Context ctx, View view, ExpandableNotificationRow row) {
657d1c63e66a2e19bf32249f52c56e563eae4c6819Selim Cinek        super(view, row);
669c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek        mIconDarkAlpha = ctx.getResources().getInteger(R.integer.doze_small_icon_alpha);
679c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek        mInvertHelper = new ViewInvertHelper(ctx, NotificationPanelView.DOZE_ANIMATION_DURATION);
684ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek        mTransformationHelper = new ViewTransformationHelper();
699c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek        resolveHeaderViews();
704ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek        updateInvertHelper();
719c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek    }
729c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek
739c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek    protected void resolveHeaderViews() {
749c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek        mIcon = (ImageView) mView.findViewById(com.android.internal.R.id.icon);
759c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek        mExpandButton = (ImageView) mView.findViewById(com.android.internal.R.id.expand_button);
769c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek        mColor = resolveColor(mExpandButton);
779c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek        mNotificationHeader = (NotificationHeaderView) mView.findViewById(
789c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek                com.android.internal.R.id.notification_header);
799c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek    }
809c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek
819c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek    private int resolveColor(ImageView icon) {
829c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek        if (icon != null && icon.getDrawable() != null) {
839c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek            ColorFilter filter = icon.getDrawable().getColorFilter();
849c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek            if (filter instanceof PorterDuffColorFilter) {
859c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek                return ((PorterDuffColorFilter) filter).getColor();
869c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek            }
879c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek        }
889c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek        return 0;
899c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek    }
909c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek
919c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek    @Override
924ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek    public void notifyContentUpdated(StatusBarNotification notification) {
9319ba7050c3aaf47f431d33341de7399df776f559Selim Cinek        super.notifyContentUpdated(notification);
9475524417ac507597b19abb2a91389044bec682adAdrian Roos
9575524417ac507597b19abb2a91389044bec682adAdrian Roos        ArraySet<View> previousViews = mTransformationHelper.getAllTransformingViews();
9675524417ac507597b19abb2a91389044bec682adAdrian Roos
979c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek        // Reinspect the notification.
989c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek        resolveHeaderViews();
994ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek        updateInvertHelper();
1004ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek        updateTransformedTypes();
101646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek        addRemainingTransformTypes();
1020ffbda62e55ad390e05e6c3ff52e1378e420285cSelim Cinek        updateCropToPaddingForImageViews();
10375524417ac507597b19abb2a91389044bec682adAdrian Roos
10475524417ac507597b19abb2a91389044bec682adAdrian Roos        // We need to reset all views that are no longer transforming in case a view was previously
10575524417ac507597b19abb2a91389044bec682adAdrian Roos        // transformed, but now we decided to transform its container instead.
10675524417ac507597b19abb2a91389044bec682adAdrian Roos        ArraySet<View> currentViews = mTransformationHelper.getAllTransformingViews();
10775524417ac507597b19abb2a91389044bec682adAdrian Roos        for (int i = 0; i < previousViews.size(); i++) {
10875524417ac507597b19abb2a91389044bec682adAdrian Roos            View view = previousViews.valueAt(i);
10975524417ac507597b19abb2a91389044bec682adAdrian Roos            if (!currentViews.contains(view)) {
11075524417ac507597b19abb2a91389044bec682adAdrian Roos                mTransformationHelper.resetTransformedView(view);
11175524417ac507597b19abb2a91389044bec682adAdrian Roos            }
11275524417ac507597b19abb2a91389044bec682adAdrian Roos        }
1130ffbda62e55ad390e05e6c3ff52e1378e420285cSelim Cinek    }
1140ffbda62e55ad390e05e6c3ff52e1378e420285cSelim Cinek
1150ffbda62e55ad390e05e6c3ff52e1378e420285cSelim Cinek    /**
116646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek     * Adds the remaining TransformTypes to the TransformHelper. This is done to make sure that each
117646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek     * child is faded automatically and doesn't have to be manually added.
118646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek     * The keys used for the views are the ids.
119646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek     */
120646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek    private void addRemainingTransformTypes() {
121646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek        mTransformationHelper.addRemainingTransformTypes(mView);
122646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek    }
123646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek
124646d2054dd76d7213ced8a73f2352f0d63f20043Selim Cinek    /**
1250ffbda62e55ad390e05e6c3ff52e1378e420285cSelim Cinek     * Since we are deactivating the clipping when transforming the ImageViews don't get clipped
1260ffbda62e55ad390e05e6c3ff52e1378e420285cSelim Cinek     * anymore during these transitions. We can avoid that by using
1270ffbda62e55ad390e05e6c3ff52e1378e420285cSelim Cinek     * {@link ImageView#setCropToPadding(boolean)} on all ImageViews.
1280ffbda62e55ad390e05e6c3ff52e1378e420285cSelim Cinek     */
1290ffbda62e55ad390e05e6c3ff52e1378e420285cSelim Cinek    private void updateCropToPaddingForImageViews() {
1300ffbda62e55ad390e05e6c3ff52e1378e420285cSelim Cinek        Stack<View> stack = new Stack<>();
1310ffbda62e55ad390e05e6c3ff52e1378e420285cSelim Cinek        stack.push(mView);
1320ffbda62e55ad390e05e6c3ff52e1378e420285cSelim Cinek        while (!stack.isEmpty()) {
1330ffbda62e55ad390e05e6c3ff52e1378e420285cSelim Cinek            View child = stack.pop();
1340ffbda62e55ad390e05e6c3ff52e1378e420285cSelim Cinek            if (child instanceof ImageView) {
1350ffbda62e55ad390e05e6c3ff52e1378e420285cSelim Cinek                ((ImageView) child).setCropToPadding(true);
1360ffbda62e55ad390e05e6c3ff52e1378e420285cSelim Cinek            } else if (child instanceof ViewGroup){
1370ffbda62e55ad390e05e6c3ff52e1378e420285cSelim Cinek                ViewGroup group = (ViewGroup) child;
1380ffbda62e55ad390e05e6c3ff52e1378e420285cSelim Cinek                for (int i = 0; i < group.getChildCount(); i++) {
1390ffbda62e55ad390e05e6c3ff52e1378e420285cSelim Cinek                    stack.push(group.getChildAt(i));
1400ffbda62e55ad390e05e6c3ff52e1378e420285cSelim Cinek                }
1410ffbda62e55ad390e05e6c3ff52e1378e420285cSelim Cinek            }
1420ffbda62e55ad390e05e6c3ff52e1378e420285cSelim Cinek        }
1434ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek    }
1444ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek
1454ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek    protected void updateInvertHelper() {
1464ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek        mInvertHelper.clearTargets();
1474ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek        for (int i = 0; i < mNotificationHeader.getChildCount(); i++) {
1484ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek            View child = mNotificationHeader.getChildAt(i);
1494ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek            if (child != mIcon) {
1504ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek                mInvertHelper.addTarget(child);
1514ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek            }
1524ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek        }
1534ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek    }
1544ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek
1554ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek    protected void updateTransformedTypes() {
1564ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek        mTransformationHelper.reset();
1578f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek        mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_HEADER,
1588f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek                mNotificationHeader);
1599c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek    }
1609c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek
1619c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek    @Override
1629c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek    public void setDark(boolean dark, boolean fade, long delay) {
163b88b98477ae725092c27dfe52f7fca3d4f29913eSelim Cinek        if (dark == mDark && mDarkInitialized) {
16419ba7050c3aaf47f431d33341de7399df776f559Selim Cinek            return;
16519ba7050c3aaf47f431d33341de7399df776f559Selim Cinek        }
16619ba7050c3aaf47f431d33341de7399df776f559Selim Cinek        super.setDark(dark, fade, delay);
1679c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek        if (fade) {
1689c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek            mInvertHelper.fade(dark, delay);
1699c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek        } else {
1709c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek            mInvertHelper.update(dark);
1719c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek        }
1727d1c63e66a2e19bf32249f52c56e563eae4c6819Selim Cinek        if (mIcon != null && !mRow.isChildInGroup()) {
1737d1c63e66a2e19bf32249f52c56e563eae4c6819Selim Cinek            // We don't update the color for children views / their icon is invisible anyway.
1747d1c63e66a2e19bf32249f52c56e563eae4c6819Selim Cinek            // It also may lead to bugs where the icon isn't correctly greyed out.
1759c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek            boolean hadColorFilter = mNotificationHeader.getOriginalIconColor()
1769c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek                    != NotificationHeaderView.NO_COLOR;
1779c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek            if (fade) {
1789c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek                if (hadColorFilter) {
1799c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek                    fadeIconColorFilter(mIcon, dark, delay);
1809c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek                    fadeIconAlpha(mIcon, dark, delay);
1819c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek                } else {
1829c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek                    fadeGrayscale(mIcon, dark, delay);
1839c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek                }
1849c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek            } else {
1859c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek                if (hadColorFilter) {
1869c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek                    updateIconColorFilter(mIcon, dark);
1879c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek                    updateIconAlpha(mIcon, dark);
1889c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek                } else {
1899c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek                    updateGrayscale(mIcon, dark);
1909c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek                }
1919c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek            }
1929c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek        }
1939c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek    }
1949c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek
1959c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek    private void fadeIconColorFilter(final ImageView target, boolean dark, long delay) {
1969c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek        startIntensityAnimation(new ValueAnimator.AnimatorUpdateListener() {
1979c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek            @Override
1989c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek            public void onAnimationUpdate(ValueAnimator animation) {
1999c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek                updateIconColorFilter(target, (Float) animation.getAnimatedValue());
2009c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek            }
2019c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek        }, dark, delay, null /* listener */);
2029c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek    }
2039c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek
2049c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek    private void fadeIconAlpha(final ImageView target, boolean dark, long delay) {
2059c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek        startIntensityAnimation(new ValueAnimator.AnimatorUpdateListener() {
2069c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek            @Override
2079c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek            public void onAnimationUpdate(ValueAnimator animation) {
2089c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek                float t = (float) animation.getAnimatedValue();
2099c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek                target.setImageAlpha((int) (255 * (1f - t) + mIconDarkAlpha * t));
2109c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek            }
2119c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek        }, dark, delay, null /* listener */);
2129c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek    }
2139c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek
2149c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek    protected void fadeGrayscale(final ImageView target, final boolean dark, long delay) {
2159c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek        startIntensityAnimation(new ValueAnimator.AnimatorUpdateListener() {
2169c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek            @Override
2179c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek            public void onAnimationUpdate(ValueAnimator animation) {
2189c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek                updateGrayscaleMatrix((float) animation.getAnimatedValue());
2199c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek                target.setColorFilter(new ColorMatrixColorFilter(mGrayscaleColorMatrix));
2209c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek            }
2219c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek        }, dark, delay, new AnimatorListenerAdapter() {
2229c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek            @Override
2239c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek            public void onAnimationEnd(Animator animation) {
2249c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek                if (!dark) {
2259c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek                    target.setColorFilter(null);
2269c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek                }
2279c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek            }
2289c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek        });
2299c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek    }
2309c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek
2319c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek    private void updateIconColorFilter(ImageView target, boolean dark) {
2329c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek        updateIconColorFilter(target, dark ? 1f : 0f);
2339c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek    }
2349c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek
2359c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek    private void updateIconColorFilter(ImageView target, float intensity) {
2369c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek        int color = interpolateColor(mColor, mIconDarkColor, intensity);
2379c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek        mIconColorFilter.setColor(color);
2389c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek        Drawable iconDrawable = target.getDrawable();
2399c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek
2409c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek        // Also, the notification might have been modified during the animation, so background
2419c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek        // might be null here.
2429c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek        if (iconDrawable != null) {
2434aad455280dd19a3097e8fad3f68bfee1de30327Adrian Roos            Drawable d = iconDrawable.mutate();
2444aad455280dd19a3097e8fad3f68bfee1de30327Adrian Roos            // DrawableContainer ignores the color filter if it's already set, so clear it first to
2454aad455280dd19a3097e8fad3f68bfee1de30327Adrian Roos            // get it set and invalidated properly.
2464aad455280dd19a3097e8fad3f68bfee1de30327Adrian Roos            d.setColorFilter(null);
2474aad455280dd19a3097e8fad3f68bfee1de30327Adrian Roos            d.setColorFilter(mIconColorFilter);
2489c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek        }
2499c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek    }
2509c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek
2519c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek    private void updateIconAlpha(ImageView target, boolean dark) {
2529c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek        target.setImageAlpha(dark ? mIconDarkAlpha : 255);
2539c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek    }
2549c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek
2559c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek    protected void updateGrayscale(ImageView target, boolean dark) {
2569c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek        if (dark) {
2579c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek            updateGrayscaleMatrix(1f);
2589c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek            target.setColorFilter(new ColorMatrixColorFilter(mGrayscaleColorMatrix));
2599c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek        } else {
2609c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek            target.setColorFilter(null);
2619c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek        }
2629c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek    }
2639c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek
2649c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek    @Override
2659c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek    public void updateExpandability(boolean expandable, View.OnClickListener onClickListener) {
2669c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek        mExpandButton.setVisibility(expandable ? View.VISIBLE : View.GONE);
2679c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek        mNotificationHeader.setOnClickListener(expandable ? onClickListener : null);
2689c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek    }
2699c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek
2709c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek    private static int interpolateColor(int source, int target, float t) {
2719c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek        int aSource = Color.alpha(source);
2729c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek        int rSource = Color.red(source);
2739c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek        int gSource = Color.green(source);
2749c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek        int bSource = Color.blue(source);
2759c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek        int aTarget = Color.alpha(target);
2769c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek        int rTarget = Color.red(target);
2779c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek        int gTarget = Color.green(target);
2789c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek        int bTarget = Color.blue(target);
2799c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek        return Color.argb(
2809c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek                (int) (aSource * (1f - t) + aTarget * t),
2819c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek                (int) (rSource * (1f - t) + rTarget * t),
2829c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek                (int) (gSource * (1f - t) + gTarget * t),
2839c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek                (int) (bSource * (1f - t) + bTarget * t));
2849c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek    }
2859c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek
2869c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek    @Override
2879c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek    public NotificationHeaderView getNotificationHeader() {
2889c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek        return mNotificationHeader;
2899c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek    }
2904ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek
2914ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek    @Override
2924ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek    public TransformState getCurrentState(int fadingView) {
2934ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek        return mTransformationHelper.getCurrentState(fadingView);
2944ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek    }
2954ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek
2964ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek    @Override
2974ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek    public void transformTo(TransformableView notification, Runnable endRunnable) {
2984ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek        mTransformationHelper.transformTo(notification, endRunnable);
2994ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek    }
3004ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek
3014ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek    @Override
3028f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek    public void transformTo(TransformableView notification, float transformationAmount) {
3038f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek        mTransformationHelper.transformTo(notification, transformationAmount);
3048f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek    }
3058f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek
3068f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek    @Override
3074ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek    public void transformFrom(TransformableView notification) {
3084ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek        mTransformationHelper.transformFrom(notification);
3094ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek    }
3104ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek
3114ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek    @Override
3128f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek    public void transformFrom(TransformableView notification, float transformationAmount) {
3138f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek        mTransformationHelper.transformFrom(notification, transformationAmount);
3148f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek    }
3158f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek
3168f2f6a67fad7aed720e33a6629cb65d368ebfb80Selim Cinek    @Override
3174ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek    public void setVisible(boolean visible) {
3184ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek        super.setVisible(visible);
3194ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek        mTransformationHelper.setVisible(visible);
3204ffd63611a0d516c9988b37e9c06e6f8390c2a2fSelim Cinek    }
3219c7712d45ccec56a80873a83e56a83f810624b43Selim Cinek}
322